开发者

How to compare two arrays of integers order-insensitively

I want Java code tha开发者_运维问答t can compare in this way (for example):

<1 2 3 4>  = <3 1 2 4>
<1 2 3 4> != <3 4 1 1>

I can't use hashmap table or anything; just pure code without library.

I know there are two ways.

  1. sort them and compare the array index by index
  2. use two for loops and compare the outer index with the inner index. I have been trying with this but still not working:

    for(int i = 0; i < n; i++)
    {
        for(int j = 0; j < n; j++)
        {   
            if(a[i] != a[j] && j == n)
                return false;
        }
    }
    return true;
    

anything wrong with the code ? thanks


Sort & compare. You can't get the complexity better than that, and any "improvement" that you do on the speed comes at the risk that your code will be wrong.

[edit] Actually.... if you know your numbers are relatively small (e.g. say: the arrays only contain numbers between 0 and 1000), that there's an alternative in O(n). Something like this (sorry if the syntax is wrong, I didn't use java lately):

int count[1001]; // already intialized to 0

for(int i=0;i<n;i++){ count[a[i]]++; count[b[i]]--;}
bool arrays_identical = true;
for(int i=0;i<=1000 && arrays_identical; i++)
    arrays_identical &= count[i]==0;

Disclaimer: this code doesn't contain "sanity checks" (i.e. the arrays are really of length "n", the numbers are in the prescribed interval) - it's only to illustrate the principle.


Arrays.sort(a);
Arrays.sort(b);
return Arrays.equals(a, b);


Since this is homework, I'm going to guess that a simple quadratic solution (which your original attempt is), is fine. In that case, you can do something like this:

int count(int[] nums, int x) {
    int count = 0;
    for (int num : nums) {
        if (num == x) count++;
    }
    return count;
}   
boolean equals(int[] arr1, int[] arr2) {
    if (arr1.length != arr2.length) return false;
    for (int x : arr1) {
        if (count(arr1, x) != count(arr2, x)) return false;
    }
    return true;
}

This sacrifices speed for clarity: it's obviously correct!!

Tips

  • Use for-each whenever applicable; it always read to better readability
  • Helper functions improve both readability and reusability!


Before you actually start a more computationally complex solution, you can run a fast O(n) test to see if the arrays are the same. There are times when this this will result in a false positive, and you can use more computationally intensive means to investigate further. If it returns false, you can be assured that the arrays are different.

The basic approach is to do a cummulative XOR between the ith elements of the two arrays. If the resulting XOR is non-zero then you know that the two arrays are different. If the XOR is zero, they might be the same, but more work is needed to confirm.

int c_xor = 0;  // XOR accumulator

for (int i = 0; i < n; ++i)
    c_xor ^= arr1[i] ^ arr2[i];

// They're different if c_xor != 0; the might be the same if c_xor == 0
return c_xor == 0;


I think it would be sensible to check that the lengths of both arrays are equal before doing any iterating. It's a cheap way to opt out of hard work early, and it fixes the following type of failure for the second approach you mention:

{1, 2, 3} seen as equal to {4, 3, 2, 1}


This is a O(n^2) problem. No other solution is faster than comparing the two arrays directly.

The Virgil's solution is cool, except for the fact that it is not really O(n) performance. It is really O(n+1000) performance. The array comparison second time to set the boolean variable is costly and backfires in small arrays.

The solution you wrote is the best except for a bugs.

Here is the error corrected version.

boolean[] matchedPositions = new boolean[n];
for(int k = 0; k < n; k++
{
    matchedPositions[k] = false;
}

for(int i = 0; i < n; i++)
{
    for(int j = 0; j < n; j++)
    {   
        if(matchedPositions[j] == false && a[i] == a[j])
        {
             matchedPositions[j] = true;
             break;
        }

        if(j == n - 1)
        {
            return false;
        }
    }
}
return true;

In this case if in case the integer matches then the inner loop will break and set or flag the matched position. This is required for arrays with duplicate entries, this will avoid two entries in left array matching with one entry in the right array.

If in case the match did not happen, which is identified by j == n - 1, you will return false.

Since we are expecting a default value of false in boolean its better to flag initialize it.

In reality, this solution has O(n log n + n) performance penalty. Sort and compare has a performance penalty of O(n^2 + n) too. Sort has O(n^2) performance and one loop for checking. But sorting changes the contents of the array and this does not.


if you take one array as 1,2,3,4,3,1,2,4 then the solution is in this way.

2n = total number of integers : 8

//program
int i, j, n = 4;
for(i = 0; i < n; i++)
  for(j = n; j < 2n; j++)
   {
     if( a[i] != a[j])
      { 
        j++;
      }
     else
     {
       i++; exit();
     }
  }  

if (i == n) 
{ //They both are equal;
}
else if(i != n)
{
//They both are not equal;
}

If it is not working please comment on it. Thank You.


Here is a fix for the code that you posted.

for(int i = 0; i < n; i++)
{
    int j;
    for(j = 0; j < n; j++)
    {   
        if(a[i] == b[j]) break;
    }
    if (j == n) return false;
}
return true;

That algorithm is going to break done for arrays that contain duplicates, however. For example, the array {1, 1, 2, 3} will be found as a match to the array {1, 2, 2, 3}.

I would highly recommend that you implement a sort-and-compare algorithm instead.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜