This problem is equivalent to the problem of the longest growing subsequence .
You will need to define a comparison operator less . less(a, b) will return true if and only if a is before b in the target sequence. Now, using this comparison operator, calculate the maximum increasing subsequence of the original sequence. You will need to transfer every element that is not part of this subsequence (otherwise the subsequence will not be maximum), and you can move it exactly once (moving it to the target position).
EDIT: As requested by Amit, this is my proof of the above statement: Denote the target sequence b and denote the original sequence a . Let n = |A| and k is the length of the longest ascending sequence as described above.
- Suppose that with
a , b can be reached with less progress than n - k . This means that at least n - k + 1 elements from a will not be moved. Let s 1 , s 2 , ... s m be a set of elements that do not move. From the assumption, we know that m > k . Now that these elements did not move, their relative position relative to each other could not change. Thus, the relative positions of all these elements in the target sequence b are the same as in a . Therefore, the operator less (s i , s j ), as defined above, must be true for any i , j . But if this is so, then s 1 , s 2 , ... s m is an increasing sequence, and as m > k this leads to a contradiction with the assumption that k is the length of the longest increasing sequence. - Now let's show the algorithm for reaching
b from a by moving all the elements except those that are part of the longest ascending sequence. We will move the elements in the order in which they appear in B. We will not move the elements that are part of the longest ascending sequence. If the current item is the first in B, we simply move it to the beginning of the sequence. Otherwise, we move the current element to the right after the position of the previous element in B. Note that this element can be either the previous element that we moved or the element from the longest increasing sequence. Please note that at each step, when we are going to move the element with index i , all elements with index 1, 2, ...i-1 will already have the correct relative positions relative to each other.
EDIT: adding some code to make the answer clearer. I do not feel like an expert in javascript, so feel free to correct or criticize my solution.
Define a transform(a, s) function that takes two parameters - lists a and b, as described in the instruction. First I will create a positions map that maps each element in a to its position in s:
var positions = {}; for (var i = 0; i < a.length; ++i) { positions[a[i]] = i; }
Now that I have this array, I can define a helper function less, as described in my answer above. It will take two values a and b less (and the just created helper map) and return true if and only if a is before b in s (target list):
function less(a, b, positions) { return positions[a] < positions[b]; }
Now I will not describe how to find the maximum increasing subsequence in a with respect to this comparison operator. You can look at this question for a detailed explanation of how to do this. I just assume that I have a function defined:
function max_increasing_subsequence(a, positions)
This returns the maximum incremental subsequence in a relative to the comparison operator less , as defined above (using positions ) as a list. I will use your second example to illustrate what we still have:
A = [9,1,2,3,0] S = [0,1,2,3,9]
The values ββin the positions will be as follows:
positions = { 0 : 0, 1 : 1, 2 : 2, 3 : 3, 9 : 4}
And the result of max_increasing_subsequence(a, positions) will be [1, 2, 3] . By the way, if elements can be repeated in a , it may be better to return indexes instead of elements from max_increasing_subsequence (in this specific example, the difference will not be visible).
Now I will create another auxiliary map to indicate which elements are included in the maximum ascending subsequence:
var included = {}; l = max_increasing_subsequence(a, positions); for (var i = 0; i < l.length; ++i) { included[l[i]] = true; }
Now you can finish the solution with a single iteration over s . I will add a special case for the last element to make the code more understandable:
if (!(s[s.length - 1] in included)) { console.log("Move" + s[s.length - 1] + " at the end"); } for (var i = s.length - 2; i >= 0; --i) { if (!(s[i] in included)) { console.log("Move" + s[i] + " before " + s[i + 1]); } }
Note that in the solution above, I assume that every time you register a new command, you register it with respect to ordering array a immediately after all previous commands have been executed.
So, in general, I think the conversion should look something like this:
function transform(a, s) { var positions = {}; for (var i = 0; i < a.length; ++i) { positions[a[i]] = i; } var included = {}; l = max_increasing_subsequence(a, positions); var included = {}; for (var i = 0; i < l.length; ++i) { included[l[i]] = true; } if (!(s[s.length - 1] in included)) { console.log("Move" + s[s.length - 1] + " at the end"); } for (var i = s.length - 2; i >= 0; --i) { // note s.length - 2 - don't process last element if (!(s[i] in included)) { console.log("Move" + s[i] + " before " + s[i + 1]); } } }
Hope this code makes my answer clearer.