views:

103

answers:

3

I have two ordered lists of the same element type, each list having at most one element of each value (say ints and unique numbers), but otherwise with no restrictions (one may be a subset of the other, they may be completely disjunct, or share some elements but not others).

How do I efficiently determine if A is ordering any two items in a different way than B is? For example, if A has the items 1, 2, 10 and B the items 2, 10, 1, the property would not hold as A lists 1 before 10 but B lists it after 10. 1, 2, 10 vs 2, 10, 5 would be perfectly valid however as A never mentions 5 at all, I cannot rely on any given sorting rule shared by both lists.

+4  A: 

You can get O(n) as follows. First, find the intersection of the two sets using hashing. Second, test whether A and B are identical if you only consider elements from the intersection.

jonderry
That's what I was thinking. Intersect the lists and compare.
Chris
O(n) to convert lists to hash based sets, O(n) to compare each list against the others lists set to form lists containing only the overlapping elements, and O(n) to compare those lists. Awesome!
Freed
A: 

My approach would be to first make sorted copies of A and B which also record the positions of elements in the original lists:

for i in 1 .. length(A):
    Apos[i] = (A, i)
sortedApos = sort(Apos[] by first element of each pair)

for i in 1 .. length(B):
    Bpos[i] = (B, i)
sortedBpos = sort(Bpos[] by first element of each pair)

Now find those elements in common using a standard list merge that records the positions in both A and B of the shared elements:

i = 1
j = 1
shared = []
while i <= length(A) && j <= length(B)
    if sortedApos[i][1] < sortedBpos[j][1]
        ++i
    else if sortedApos[i][1] > sortedBpos[j][1]
        ++j
    else    // They're equal
        append(shared, (sortedApos[i][2], sortedBpos[j][2]))
        ++i
        ++j

Finally, sort shared by its first element (position in A) and check that all its second elements (positions in B) are increasing. This will be the case iff the elements common to A and B appear in the same order:

sortedShared = sort(shared[] by first element of each pair)
for i = 2 .. length(sortedShared)
    if sortedShared[i][2] < sortedShared[i-1][2]
        return DIFFERENT

return SAME

Time complexity: 2*(O(n) + O(nlog n)) + O(n) + O(nlog n) + O(n) = O(nlog n).

j_random_hacker
A: 

General approach: store all the values and their positions in B as keys and values in a HashMap. Iterate over the values in A and look them up in B's HashMap to get their position in B (or null). If this position is before the largest position value you've seen previously, then you know that something in B is in a different order than A. Runs in O(n) time.

Rough, totally untested code:

boolean valuesInSameOrder(int[] A, int[] B)
{
  Map<Integer, Integer> bMap = new HashMap<Integer, Integer>();
  for (int i = 0; i < B.length; i++)
  {
    bMap.put(B[i], i);
  }

  int maxPosInB = 0;
  for (int i = 0; i < A.length; i++)
  {
    if(bMap.containsKey(A[i]))
    {
      int currPosInB = bMap.get(A[i]);
      if (currPosInB < maxPosInB)
      {
        // B has something in a different order than A
        return false;
      }
      else
      {
        maxPosInB = currPosInB;
      }
    }
  }

  // All of B's values are in the same order as A
  return true;
}
Yevgeniy Brikman
O(n) indeed, nice!
Freed