I have an array of M integers. I have to find all possible integers K (given there is at least 1 K)such that:
1) K > 1
2) arr[0]%K = arr[1]%K = arr[2]%K = ... = arr[M-1]%K
What is the best algorithm for this problem?
K
, we know that, for example, the array arr
such that arr[0]=4; arr[1]=6; arr[2]=9
is not valid because no modulus gives the same result for each.K
> 1, we know that all values of the array cannot be the same. They are, however, the same modK
for all K
.Keep in mind that arr[i]%K
(for any i such that 0=<i<M
) does not have to be positive.
Code has not been tested
It seems to me as if the simplest way of determining K
values will be from finding the differences between each value in the array. (I'm going to show examples in Java.) Let's say that arrDiff
contains the differences of each value such that
arrDiff[0] = arr[0]-arr[1];
arrDiff[1] = arr[1] - arr[2];
...
arrDiff[M-1] = arr[M-1] - arr[0];
Now, find G = gcd(arrDiff[0],arrDiff[1],...,arrDiff[M-1]
to find all valid K
. You can use whatever gcd
method you wish, which is the Euclidean Algorithm, in order to iteratively/recursively find
G
. You can also ignore negative differences since gcd
will give you positive results.
[All of G's factors]>1
(including G
itself) will be valid K
values.
I'm not going to do a proof (I'll leave that to you), but let's do an example just to be clear.
arr
//Let's do an easy one with M=3
int arr[] = new int[3];
arr[0] = -7;
arr[1] = 9;
arr[2] = 25
I'll show a slightly more efficient implementation here (thanks to @RBarryYoung).
int min = findSmallestNumber(arr); //Returns min value (may be negative)
//The array size is intended to not include the minimum, assuming we have no duplicates.
int arrDiff[] = new int[arr.length-1];
for(int num : arr){
if(num==min) continue;
arrDiff[num] = arr[num] - min;
}
For the example above, this code should give us values of 16,32
in arrDiff
. Notice that using this method should result in all positive values for gcd calculations in the next step.
G = gcd
I'm not going to write a gcd method for you, since there are lots of implementations; I'll assume you have a method int gcd(int a, int b)
.
int g = gcd(arrDiff[0], arrDiff[1]);
for(int i = 2, i < arrDiff.length-1, i++){
g = gcd(g, arrDiff[i]);
}
//return g;
Note that if we only have two values in the array, no gcd
usage is necessary--just use the single difference.
For our example, you can easily find that the gcd(-16,-16,32)=gcd(16,16,32)=16. Thus 16 and all of its factors >1 should be answers. Let's check 16 at least. Note that the below "=" should really be a congruence symbol (three bars not two).
-7mod16 = 9mod16
9mod16 = 9mod16
25mod16 = 9mod16
You can check that this also works for factors 2,4,8
. (For all of these factors, you should get 1mod8 => 1mod4 => 1mod2
.)
If you have to find the factors in code, you may be interested in one of the various factoring algorithms to find all factors of G
greater than 1. Picking the most optimized may depend on your data.
Thus, it's really a combination of algorithms which you may need. There may be slightly faster ways of doing what I showed you above, but the basic algorithm should be approachable now.