Suppose we have two unsorted arrays, A[1...m] and B[1...n]. The objective is to return an array C[1...(m+n)] formed by interleaving the elements from A and B (in other words, A[i] must precede A[i+1] and B[i] must precede B[i+1] in C) such that C is as large as possible in lexicographical order. What are some approaches to solve this problem in linear time?
The basic approach is greedy: if A[i] is bigger than B[j], then take A[i] and increment i, or else if B[j] is bigger than A[i] then take B[j] and increment j. The difficulty arises when A[i] and B[j] are equal. In this case we have to "look ahead" to find the first position k such that A[i+k] and B[j+k] differ. The code in C++ looks like this:
// A, B are the input vectors
vector<int> C;
auto it1 = A.begin();
auto it2 = B.begin();
while (it1 != A.end() || it2 != B.end()) {
if (std::lexicographical_compare(it1, A.end(), it2, B.end())) {
C.push_back(*it2++);
} else {
C.push_back(*it1++);
}
}
Because of the requirement to look ahead, this can take quadratic time.
One approach to do it in linear time is to concatenate the two arrays with a separator that is guaranteed to compare less with all elements of the original arrays, compute the suffix array of this combined array, and use that in order to easily look up which suffix is greater instead of doing a full scan in every iteration of the while loop.
- As suffix array construction is relatively complicated, I am interested in whether simpler approaches exist.
- In addition, a suffix array uses linear extra memory and I am wondering whether there is a solution that takes linear time and only uses constant extra memory. (By this I mean that the memory occupied by the output array C doesn't count toward the limit, but you are only allowed to append to C, and thereafter may not go back to read or write any previous elements of C.)