When you have a single array, going through it is simple: you start at the first item and move forward one step at a time until you reach the end. But sometimes a problem gives you two lists of data, and you need to work with items from both lists together. The *simultaneous traversal* technique is how we do this — we walk through both arrays at the same time, in a single pass.
Imagine two friends reading two different books side by side, comparing one page at a time. Each friend keeps a finger on their current page. After comparing, maybe one friend turns a page, maybe the other does, or maybe both do — it depends on what they just saw.
That is exactly the idea here:
arr1 and arr2. They can be different sizes.index1 for the first array and index2 for the second.arr1[index1] and arr2[index2]), apply some function or comparison, and then decide which finger to move forward.The key difference from normal traversal: we don't blindly move both fingers every time. Based on a condition, we may advance only one of them, or both of them.
Many real problems need this pattern. The classic example is merging two sorted lists into one sorted list. You look at the front of each list, take the smaller value, and move forward only in the list you took from. Other examples include finding common elements between two sorted arrays, or combining two sequences.
The big win is efficiency: instead of going through one array completely for every item of the other (which would be slow), you sweep through both just once.
Picture both fingers starting at position 0:
arr1[index1] with arr2[index2].Sometimes index1 jumps ahead while index2 stays put. A few steps later it might be the opposite. Slowly, both fingers crawl toward the ends of their arrays. Because the two arrays have different lengths, one of them will usually run out first.
The main loop keeps going only while both fingers are still inside their arrays. The moment one array is fully used up, the loop stops — even if the other array still has items waiting.
So after the loop, we check: did one array still have leftover items? If yes, we simply walk through whatever remains in that array and process those items too. This "clean up the rest" step makes sure no data is missed.
The version below moves from start to end in both arrays, advancing one step at a time:
index1 = 0 and index2 = 0.index1 < arr1.size() and index2 < arr2.size():arr1[index1] and increment index1.arr2[index2] and increment index2.arr1 still has items left, walk through the rest using index1 and process them.arr2 still has items left, walk through the rest using index2 and process them.void simultaneousTraversal(vector<int>& arr1, vector<int>& arr2) {
// Initialize index variables for two arrays
int index1 = 0, index2 = 0;
// Traverse both arrays simultaneously until
// the end of any one array is reached
while(index1 < arr1.size() && index2 < arr2.size()) {
if(shouldMoveFirst) { // Replace this with actual condition
// Process arr1[index1]
// ....
index1++;
}
if(shouldMoveSecond) { // Replace this with actual condition
// Process arr2[index2]
// ....
index2++;
}
}
// (Afterwards, process any leftover items in whichever array is not finished.)
}
Here shouldMoveFirst and shouldMoveSecond are placeholders. In a real problem you replace them with your actual rule — for example, "move in the array whose current value is smaller."
This pattern is flexible. You can change:
The structure stays the same; only the details change.
N and M, the total work grows in line with N + M, so the time complexity is O(N + M) — linear.O(1).This holds for both the best and worst cases, which makes the technique fast and memory-friendly.