Off-by-one on range boundaries
Wrong move: Loop endpoints miss first/last candidate.
Usually fails on: Fails on minimal arrays and exact-boundary answers.
Fix: Re-derive loops from inclusive/exclusive ranges before coding.
Break down a hard problem into reliable checkpoints, edge-case handling, and complexity trade-offs.
You are given a 0-indexed 2D integer array pairs where pairs[i] = [starti, endi]. An arrangement of pairs is valid if for every index i where 1 <= i < pairs.length, we have endi-1 == starti.
Return any valid arrangement of pairs.
Note: The inputs will be generated such that there exists a valid arrangement of pairs.
Example 1:
Input: pairs = [[5,1],[4,5],[11,9],[9,4]] Output: [[11,9],[9,4],[4,5],[5,1]] Explanation: This is a valid arrangement since endi-1 always equals starti. end0 = 9 == 9 = start1 end1 = 4 == 4 = start2 end2 = 5 == 5 = start3
Example 2:
Input: pairs = [[1,3],[3,2],[2,1]] Output: [[1,3],[3,2],[2,1]] Explanation: This is a valid arrangement since endi-1 always equals starti. end0 = 3 == 3 = start1 end1 = 2 == 2 = start2 The arrangements [[2,1],[1,3],[3,2]] and [[3,2],[2,1],[1,3]] are also valid.
Example 3:
Input: pairs = [[1,2],[1,3],[2,1]] Output: [[1,2],[2,1],[1,3]] Explanation: This is a valid arrangement since endi-1 always equals starti. end0 = 2 == 2 = start1 end1 = 1 == 1 = start2
Constraints:
1 <= pairs.length <= 105pairs[i].length == 20 <= starti, endi <= 109starti != endipairs.Problem summary: You are given a 0-indexed 2D integer array pairs where pairs[i] = [starti, endi]. An arrangement of pairs is valid if for every index i where 1 <= i < pairs.length, we have endi-1 == starti. Return any valid arrangement of pairs. Note: The inputs will be generated such that there exists a valid arrangement of pairs.
Start with the most direct exhaustive search. That gives a correctness anchor before optimizing.
Pattern signal: Array
[[5,1],[4,5],[11,9],[9,4]]
[[1,3],[3,2],[2,1]]
[[1,2],[1,3],[2,1]]
reconstruct-itinerary)find-if-path-exists-in-graph)Source-backed implementations are provided below for direct study and interview prep.
// Accepted solution for LeetCode #2097: Valid Arrangement of Pairs
class Solution {
public int[][] validArrangement(int[][] pairs) {
List<int[]> ans = new ArrayList<>();
Map<Integer, Deque<Integer>> graph = new HashMap<>();
Map<Integer, Integer> outDegree = new HashMap<>();
Map<Integer, Integer> inDegrees = new HashMap<>();
for (int[] pair : pairs) {
final int start = pair[0];
final int end = pair[1];
graph.putIfAbsent(start, new ArrayDeque<>());
graph.get(start).push(end);
outDegree.merge(start, 1, Integer::sum);
inDegrees.merge(end, 1, Integer::sum);
}
final int startNode = getStartNode(graph, outDegree, inDegrees, pairs);
euler(graph, startNode, ans);
Collections.reverse(ans);
return ans.stream().toArray(int[][] ::new);
}
private int getStartNode(Map<Integer, Deque<Integer>> graph, Map<Integer, Integer> outDegree,
Map<Integer, Integer> inDegrees, int[][] pairs) {
for (final int u : graph.keySet())
if (outDegree.getOrDefault(u, 0) - inDegrees.getOrDefault(u, 0) == 1)
return u;
return pairs[0][0]; // Arbitrarily choose a node.
}
private void euler(Map<Integer, Deque<Integer>> graph, int u, List<int[]> ans) {
Deque<Integer> stack = graph.get(u);
while (stack != null && !stack.isEmpty()) {
final int v = stack.pop();
euler(graph, v, ans);
ans.add(new int[] {u, v});
}
}
}
// Accepted solution for LeetCode #2097: Valid Arrangement of Pairs
// Auto-generated Go example from java.
func exampleSolution() {
}
// Reference (java):
// // Accepted solution for LeetCode #2097: Valid Arrangement of Pairs
// class Solution {
// public int[][] validArrangement(int[][] pairs) {
// List<int[]> ans = new ArrayList<>();
// Map<Integer, Deque<Integer>> graph = new HashMap<>();
// Map<Integer, Integer> outDegree = new HashMap<>();
// Map<Integer, Integer> inDegrees = new HashMap<>();
//
// for (int[] pair : pairs) {
// final int start = pair[0];
// final int end = pair[1];
// graph.putIfAbsent(start, new ArrayDeque<>());
// graph.get(start).push(end);
// outDegree.merge(start, 1, Integer::sum);
// inDegrees.merge(end, 1, Integer::sum);
// }
//
// final int startNode = getStartNode(graph, outDegree, inDegrees, pairs);
// euler(graph, startNode, ans);
// Collections.reverse(ans);
// return ans.stream().toArray(int[][] ::new);
// }
//
// private int getStartNode(Map<Integer, Deque<Integer>> graph, Map<Integer, Integer> outDegree,
// Map<Integer, Integer> inDegrees, int[][] pairs) {
// for (final int u : graph.keySet())
// if (outDegree.getOrDefault(u, 0) - inDegrees.getOrDefault(u, 0) == 1)
// return u;
// return pairs[0][0]; // Arbitrarily choose a node.
// }
//
// private void euler(Map<Integer, Deque<Integer>> graph, int u, List<int[]> ans) {
// Deque<Integer> stack = graph.get(u);
// while (stack != null && !stack.isEmpty()) {
// final int v = stack.pop();
// euler(graph, v, ans);
// ans.add(new int[] {u, v});
// }
// }
// }
# Accepted solution for LeetCode #2097: Valid Arrangement of Pairs
class Solution:
def validArrangement(self, pairs: list[list[int]]) -> list[list[int]]:
ans = []
graph = collections.defaultdict(list)
outDegree = collections.Counter()
inDegrees = collections.Counter()
for start, end in pairs:
graph[start].append(end)
outDegree[start] += 1
inDegrees[end] += 1
def getStartNode() -> int:
for u in graph.keys():
if outDegree[u] - inDegrees[u] == 1:
return u
return pairs[0][0] # Arbitrarily choose a node.
def euler(u: int) -> None:
stack = graph[u]
while stack:
v = stack.pop()
euler(v)
ans.append([u, v])
euler(getStartNode())
return ans[::-1]
// Accepted solution for LeetCode #2097: Valid Arrangement of Pairs
/**
* [2097] Valid Arrangement of Pairs
*
* You are given a 0-indexed 2D integer array pairs where pairs[i] = [starti, endi]. An arrangement of pairs is valid if for every index i where 1 <= i < pairs.length, we have endi-1 == starti.
* Return any valid arrangement of pairs.
* Note: The inputs will be generated such that there exists a valid arrangement of pairs.
*
* Example 1:
*
* Input: pairs = [[5,1],[4,5],[11,9],[9,4]]
* Output: [[11,9],[9,4],[4,5],[5,1]]
* Explanation:
* This is a valid arrangement since endi-1 always equals starti.
* end0 = 9 == 9 = start1
* end1 = 4 == 4 = start2
* end2 = 5 == 5 = start3
*
* Example 2:
*
* Input: pairs = [[1,3],[3,2],[2,1]]
* Output: [[1,3],[3,2],[2,1]]
* Explanation:
* This is a valid arrangement since endi-1 always equals starti.
* end0 = 3 == 3 = start1
* end1 = 2 == 2 = start2
* The arrangements [[2,1],[1,3],[3,2]] and [[3,2],[2,1],[1,3]] are also valid.
*
* Example 3:
*
* Input: pairs = [[1,2],[1,3],[2,1]]
* Output: [[1,2],[2,1],[1,3]]
* Explanation:
* This is a valid arrangement since endi-1 always equals starti.
* end0 = 2 == 2 = start1
* end1 = 1 == 1 = start2
*
*
* Constraints:
*
* 1 <= pairs.length <= 10^5
* pairs[i].length == 2
* 0 <= starti, endi <= 10^9
* starti != endi
* No two pairs are exactly the same.
* There exists a valid arrangement of pairs.
*
*/
pub struct Solution {}
// problem: https://leetcode.com/problems/valid-arrangement-of-pairs/
// discuss: https://leetcode.com/problems/valid-arrangement-of-pairs/discuss/?currentPage=1&orderBy=most_votes&query=
// submission codes start here
impl Solution {
pub fn valid_arrangement(pairs: Vec<Vec<i32>>) -> Vec<Vec<i32>> {
vec![]
}
}
// submission codes end
#[cfg(test)]
mod tests {
use super::*;
#[test]
#[ignore]
fn test_2097_example_1() {
let pairs = vec![vec![5, 1], vec![4, 5], vec![11, 9], vec![9, 4]];
let result = vec![vec![11, 9], vec![9, 4], vec![4, 5], vec![5, 1]];
assert_eq!(Solution::valid_arrangement(pairs), result);
}
#[test]
#[ignore]
fn test_2097_example_2() {
let pairs = vec![vec![1, 3], vec![3, 2], vec![2, 1]];
let result = vec![vec![1, 3], vec![3, 2], vec![2, 1]];
assert_eq!(Solution::valid_arrangement(pairs), result);
}
#[test]
#[ignore]
fn test_2097_example_3() {
let pairs = vec![vec![1, 2], vec![1, 3], vec![2, 1]];
let result = vec![vec![1, 2], vec![2, 1], vec![1, 3]];
assert_eq!(Solution::valid_arrangement(pairs), result);
}
}
// Accepted solution for LeetCode #2097: Valid Arrangement of Pairs
// Auto-generated TypeScript example from java.
function exampleSolution(): void {
}
// Reference (java):
// // Accepted solution for LeetCode #2097: Valid Arrangement of Pairs
// class Solution {
// public int[][] validArrangement(int[][] pairs) {
// List<int[]> ans = new ArrayList<>();
// Map<Integer, Deque<Integer>> graph = new HashMap<>();
// Map<Integer, Integer> outDegree = new HashMap<>();
// Map<Integer, Integer> inDegrees = new HashMap<>();
//
// for (int[] pair : pairs) {
// final int start = pair[0];
// final int end = pair[1];
// graph.putIfAbsent(start, new ArrayDeque<>());
// graph.get(start).push(end);
// outDegree.merge(start, 1, Integer::sum);
// inDegrees.merge(end, 1, Integer::sum);
// }
//
// final int startNode = getStartNode(graph, outDegree, inDegrees, pairs);
// euler(graph, startNode, ans);
// Collections.reverse(ans);
// return ans.stream().toArray(int[][] ::new);
// }
//
// private int getStartNode(Map<Integer, Deque<Integer>> graph, Map<Integer, Integer> outDegree,
// Map<Integer, Integer> inDegrees, int[][] pairs) {
// for (final int u : graph.keySet())
// if (outDegree.getOrDefault(u, 0) - inDegrees.getOrDefault(u, 0) == 1)
// return u;
// return pairs[0][0]; // Arbitrarily choose a node.
// }
//
// private void euler(Map<Integer, Deque<Integer>> graph, int u, List<int[]> ans) {
// Deque<Integer> stack = graph.get(u);
// while (stack != null && !stack.isEmpty()) {
// final int v = stack.pop();
// euler(graph, v, ans);
// ans.add(new int[] {u, v});
// }
// }
// }
Use this to step through a reusable interview workflow for this problem.
Two nested loops check every pair or subarray. The outer loop fixes a starting point, the inner loop extends or searches. For n elements this gives up to n²/2 operations. No extra space, but the quadratic time is prohibitive for large inputs.
Most array problems have an O(n²) brute force (nested loops) and an O(n) optimal (single pass with clever state tracking). The key is identifying what information to maintain as you scan: a running max, a prefix sum, a hash map of seen values, or two pointers.
Review these before coding to avoid predictable interview regressions.
Wrong move: Loop endpoints miss first/last candidate.
Usually fails on: Fails on minimal arrays and exact-boundary answers.
Fix: Re-derive loops from inclusive/exclusive ranges before coding.