7

I have two integer array each of same size say n ( n is variable, so I can have two arrays of size say 4 or 5 or 6 etc ) and the range of values that each digit can take is in the range of 0-9. Example

Integer[] one = {1,9,3,4} 
Integer[] two = {1,1,9,3}

Now, I want to compare array one & two such that 1) I can get the count of numbers of elements which are same and at the same position. 2) I can get the count of number which are same but not at the same position .

The approach I have taken is

For (1) Iterate through array one and for each index i check one[i] == two[i]. - simple .

For (2) Iterate over both the arrays and for i != j see if the elements are same , if same mark them with -1 to avoid future conflicts.

for(int i =0;i<one.length;i++){
    for(int j=0;j<two.length;j++){
        if(i != j && one[i] != -1 && two[j] !=-1)){
            if(one[i] == two[j]){
                whiteCount++
                one[i] = -1;
                two[j] = -1;
            }
        }
    }
}

Question : Now I want to know if there is a faster way to do the same thing ? Esp. calculating the (2)nd part of the problem. This is a basic comparison method to get black and white pegs calculation for Mastermind board game . Thanks Shakti

UPDATE 1: 1) Rudi's suggestion changed Integer[] to int[]

2) Used Dave Challis's solution Change in performance for 7776 X 7776 calculations

OLD 46950 ms
NEW 42887 ms
Shakti
  • 2,013
  • 8
  • 27
  • 40
  • @lpratlong OP is also asking to get numbers in the same position. – Christian Tapia Jun 02 '14 at 09:30
  • @Ipratlong - I dont' think so – Shakti Jun 02 '14 at 09:30
  • Ok. I remove flag. Sorry for that. – lpratlong Jun 02 '14 at 09:31
  • 1
    Are you after [Levenshtein Distance](http://en.wikipedia.org/wiki/Levenshtein_distance)? – bobah Jun 02 '14 at 09:41
  • Is your goal only getting true/false for comparison of the two arrays? – Boris Jun 02 '14 at 09:42
  • You could use `int` instead of `Integer` which would improve performance esp for larger arrays. – Peter Lawrey Jun 02 '14 at 09:43
  • You now have n^2 complexity. What is you sort them first and then run once checking both. 2 * nlog n + n to run over it. This will make it fast with big n's not so sure bout the smaller examples – Montaldo Jun 02 '14 at 09:44
  • Yes, use maps and do a single scan per array! – Oleg Sklyar Jun 02 '14 at 09:49
  • This is a basic comparison method to get count of black and white pegs for mastermind game . Updated the question – Shakti Jun 02 '14 at 09:57
  • 1
    What about multiple matches? How do you expect to handle those. e.g. `Integer[] one = {1,9,2,1};` and `Integer[] two = {6,1,7,4};`. How many matches do you expect here? 1 or 2 for your **2)** case? – Eypros Jun 02 '14 at 10:02
  • @Eypros andwer (0,1) - 0 exact matches and 1 match at a different location. Once a match is found it is updated to -1 so u can't use it again. – Shakti Jun 02 '14 at 10:09
  • 2
    BTW, I'd also recommend using visualvm or similar to profile your code, and find out where most of the time is actually taken, it should give you some hints as to which bits of code to spend time on optimising. – Dave Challis Jun 03 '14 at 17:03
  • @Shakti, So did you find a proper solution? – Gary Chen Dec 09 '20 at 02:01

4 Answers4

5

Although this probably isn't exactly what your looking for, we could reduce the number of operations significantly with a very simple change.

From

Integer[] one = {1,9,3,4} 
Integer[] two = {1,1,9,3}

to

int[] one = {1,9,3,4} 
int[] two = {1,1,9,3}

This will speed up the process by a small amount, but not by optimizing the sorting/searching logic itself. All we're doing there is removing the auto-boxing and auto-unboxing operations. If however your doing this on a very large scale then this can make a substantial difference.

Rudi Kershaw
  • 12,332
  • 7
  • 52
  • 77
3

To get the count of the number of number which are the same, but at different positions, you can do this.

public static long[] encode(int... nums) {
    long[] ret = new long[nums.length];
    for (int i = 0; i < nums.length; i++) {
        ret[i] = ((long) nums << 32) + i;
    }
    Arrays.sort(ret);
}

// encode both arrays and do a merge sort, skipping matches which have the same index.

This is an O(n log N) operation.


You could move the one[i] != -1 check out so it can skip that value.

int[] one = {1,9,3,4}; // Using int is faster and clearer.
int[] two = {1,1,9,3};

for (int i = 0; i < one.length; i++){
    if (one[i] == -1) continue;
    for (int j = 0; j < two.length; j++){
        if (one[i] == two[j] && i != j && two[j] != -1) {
            whiteCount++
            one[i] = -1;
            two[j] = -1;
        }
    }
}

Putting the one[i] == two[j] first improves performance because it will usually be false so the other things don't need to be checked.

Peter Lawrey
  • 525,659
  • 79
  • 751
  • 1,130
3

The solution below is O(2N), doesn't use any additional libraries, and doesn't modify the initial arrays.

It loops through both arrays once to get a count of integers at the same position. While it does this, it builds up a count of each number in the 2nd array (and stores in the counts array).

It then loops through the first array again, getting the total number of times each number was found in the 2nd array:

final Integer[] one = {1,9,3,4};
final Integer[] two = {1,1,9,3};

int samePositionCount = 0;
int sameNumberCount = 0;

// tracks number of times an int is in the 2nd array
final Integer[] counts = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};

for (int i = 0; i < one.length; i++) {
    if (one[i].equals(two[i])) {
        samePositionCount++;
        counts[one[i]] = -1; // mark as seen in same position count
    } else if (counts[two[i]] != -1) {
        counts[two[i]]++;
    }
}

for (int i : one) {
    if (counts[i] > 0) {
        sameNumberCount += counts[i];
        counts[i] = 0; // avoid adding twice
    }
}

System.out.println(samePositionCount + " " + sameNumberCount);

Prints:

1 2
Dave Challis
  • 3,525
  • 2
  • 37
  • 65
  • The original post says that each integer can take the range 0-9, so I used a fixed sized array here. If that wasn't the case, I'd swap to using a Map of some sort. – Dave Challis Jun 02 '14 at 10:23
  • @DaveChallis - Answer should be 1,2 . First index 1 matches in both the numbers and 9,3 both present but at a different location – Shakti Jun 02 '14 at 10:25
  • @Shakti easy to fix that – Liviu Stirb Jun 02 '14 at 10:36
  • @Shakti ah, sorry, missed the part about not counting matches in the 2nd part if they're already in the first. I'll fix the answer to take that into account. – Dave Challis Jun 02 '14 at 10:38
  • 1
    @Shakti fixed now, by storing a value of -1 in `counts` if a value is matched at a position. – Dave Challis Jun 02 '14 at 10:48
  • O(2n) does not exist, it is simply O(n). – Nate Neuhaus Nov 14 '16 at 01:47
  • @NateNeuhaus sure O(N) = O(2N), I was just abusing the notation to try and get additional info through :) – Dave Challis Nov 14 '16 at 12:16
  • Abusing notation is not important, what is important is using (or abusing) the notation in a way that actually has meaning. Big O notation is simply used to put an upper bound on the growth of the function with respect to its input size. Since constants do not grow, when you include them in your Big-O analysis you are literally saying "this function grows by this additional amount that does not grow". It's simply a nonsensical statement. – Nate Neuhaus Nov 16 '16 at 05:56
  • O(2N) is perfectly valid, it's just equivalent to O(N). Similarly, I don't have an issue with seeing people use e.g. O(N³ + N² + N) to help give some indication as to the parts of code/algorithms that might be involved, even though it would be canonically written as O(N³) (i.e. the upper bound). – Dave Challis Nov 16 '16 at 10:45
  • It is perfectly valid according to whom? You? It is meaningless, and all who come across your post should be duly warned that providing such a answer in a tech interview will only show the interviewer that you do not understand complexity theory. – Nate Neuhaus Nov 18 '16 at 01:19
  • According to the definition of big O. O(2N) = O(3N+1) = O(N), which is why it's canonical to write O(N). I'm not arguing that O(2N) is faster/slower than O(N). Some discussions on SO: http://stackoverflow.com/questions/25777714/which-algorithm-is-faster-on-or-o2n , Quora (https://www.quora.com/In-big-O-notations-why-O-2n-is-equal-to-O-n) etc. – Dave Challis Nov 18 '16 at 10:00
  • Sigh. You misunderstand, young Padawan. O(2n) is equivalent O(n) in the same way that "and and" is logically equivalent to just saying "and", however that does not mean that it makes any sense to use it. The whole point of Big-O notation is to describe the GROWTH of a function, this is why adding non-growing constants is not more precise, but rather less credible in displaying your understanding of the fundamentals. This is why no scholarly resources ever tell you to write O(2n), and only the goofballs on the internet that lack education on the subject do. Please do not perpetuate ignorance. – Nate Neuhaus Nov 18 '16 at 23:10
0

Why not use the existing utility methods for comparing the aaarays. They are definitely faster. You can check the implemetation of "equals" method and confirm.

import java.util.Arrays;

class Test {
public static void main(String[] args) {
    int inarr1[] = {1, 2, 3};
    int inarr2[] = {1, 2, 3};
    Object[] arr1 = {inarr1};
    Object[] arr2 = {inarr2};
    if (Arrays.deepEquals(arr1, arr2))
        System.out.println("Same");
    else
        System.out.println("Not same");
   }

}

Ranjeet
  • 393
  • 2
  • 10