3

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?

ZX9
  • 898
  • 2
  • 16
  • 34
sanapala mohanarao
  • 321
  • 1
  • 2
  • 16

3 Answers3

5

First, let's examine the givens.

  • Given that there exists at least one 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.
  • Given that 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.

A Proposed Algorithm

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.

Walking Through It

I'm not going to do a proof (I'll leave that to you), but let's do an example just to be clear.

Initialize an example arr

//Let's do an easy one with M=3
int arr[] = new int[3];
arr[0] = -7;
arr[1] = 9;
arr[2] = 25

Create the difference array

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.

Calculate 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.

Checking the Example

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.)

Wrap-up

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.

ZX9
  • 898
  • 2
  • 16
  • 34
  • 1
    You can normalize this more by changing the differencing from `diff[i] = arr[i] - arr[i+1]` to `diff[i] = arr[i] - m`, (removing any zeroes) where `m` is the least element of `arr[]`. This will make all the diffs positive and eliminates the need to handle the weirdness that many language's mod functions have with negative numbers. – RBarryYoung Oct 25 '16 at 13:02
  • 1
    @RBarryYoung Ahh, you are correct. My apologies and thank you. Updating the question. – ZX9 Oct 25 '16 at 13:06
  • @sanapalamohanarao Glad to hear it! Thanks for a good question. ;) – ZX9 Oct 25 '16 at 17:20
  • 1
    @ZX9, a small problem is there, if n==2, we have only one element in difference array (diff[0]). We cannot find GCD(diff[0],diff[1]). in that situation. I just used diff[0] as GCD. Thank You – sanapala mohanarao Oct 25 '16 at 17:28
1
#include <stdio.h>
int GCD(int a, int b) {
    while(a!=b) {
        if(a>b) a-=b; else b-=a;
    }
    return a;
}
int main()
{
   int n; scanf("%d",&n);
   int a[n],i,j;
   for(i=0;i<n;i++) {
    scanf("%d",&a[i]);
   }
   //finding minimum
  int min=a[0]; for(i=0;i<n;i++) if(min>a[i]) min=a[i];

  //finding differences and storing except minimum
  int diff[n-1]; for(i=0,j=0;i<n;i++) if(a[i]!=min) diff[j++]=a[i]-min;

  // if n is 2, we have only diff[1], otherwise we can follow algo
  int g=(n==2)?diff[0]:GCD(diff[0],diff[1]); for(i=2;i<n-1;i++) g=GCD(g,diff[i]);

  //finding divisors of the final gcd.
  for(i=2;i<=g;i++) if(g%i==0)printf("%d ",i);
return 0;
}
sanapala mohanarao
  • 321
  • 1
  • 2
  • 16
0

Here's my code to the problem

#include<bits/stdc++.h>
using namespace std;

void printEqualModNumbers (int arr[], int n) 
{ 
    sort(arr, arr + n);  
    int d = arr[n-1] - arr[0]; 

    vector <int> v; 
    for (int i=2; i*i<=d; i++) 
    { 
        if (d%i == 0) 
        { 
            v.push_back(i); 
            if (i != d/i) 
                v.push_back(d/i); 
        } 
    } 
    for (int i=0; i<v.size(); i++) 
    { 
        int temp = arr[0]%v[i]; 

        int j; 
        for (j=1; j<n; j++) 
            if (arr[j] % v[i] != temp) 
                break; 

        if (j == n) 
            cout << v[i] <<" "; 
    } 
} 

int main(){
    int n;
    cin >> n;
    int arr[n];
    for(int i = 0 ; i < n ; i++)
        cin >> arr[i];

    printEqualModNumbers(arr, n);
}
m02ph3u5
  • 3,022
  • 7
  • 38
  • 51
Karn3003
  • 1
  • 3