找到每个K,使arr [i]%K等于每个arr [i]

时间:2016-10-25 11:19:31

标签: algorithm math greatest-common-divisor modular-arithmetic

我有一个M个整数数组。我必须找到所有可能的整数K(假设至少有1 K),这样:

1) K > 1
2) arr[0]%K = arr[1]%K = arr[2]%K = ... = arr[M-1]%K 

这个问题的最佳算法是什么?

3 个答案:

答案 0 :(得分:3)

首先,让我们检查一下。

  • 鉴于至少存在一个K ,我们知道,例如,数组arrarr[0]=4; arr[1]=6; arr[2]=9 是无效的,因为没有模数给出了相同的结果。
  • 鉴于K> 1,我们知道数组的所有值都不能相同。但是,对于所有modK,它们都是K

请注意,arr[i]%K(对于任何0=<i<M}并非必须是正面的。

提议的算法

代码尚未经过测试

在我看来,确定K值的最简单方法是找出数组中每个值之间的差异。 (我将在Java中展示示例。)让我们说arrDiff包含每个值的差异,以便

arrDiff[0] = arr[0]-arr[1];
arrDiff[1] = arr[1] - arr[2];
...
arrDiff[M-1] = arr[M-1] - arr[0];

现在,找到G = gcd(arrDiff[0],arrDiff[1],...,arrDiff[M-1]以查找所有有效的K。您可以使用任何gcd方法,即Euclidean Algorithm,以便迭代/递归查找 G。您也可以忽略负面差异,因为gcd会给您带来积极的结果。

[All of G's factors]>1(包括G本身)将是有效的K值。

走过它

我不打算做证明(我会留给你),但为了清楚起见,我们举个例子。

初始化示例arr

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

创建差异数组

我会在这里展示一个稍微高效的实现(感谢@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;
}

对于上面的示例,此代码应在16,32中为我们提供arrDiff的值。请注意,使用此方法应在下一步中为gcd计算生成所有正值。

计算G = gcd

我不会为你写一个gcd方法,因为有很多实现;我假设你有一个方法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; 

请注意,如果我们在数组中只有两个值,则不需要使用gcd - 只需使用单个差异。

检查示例

对于我们的例子,你可以很容易地发现gcd(-16,-16,32)= gcd(16,16,32)= 16。因此,16及其所有因子> 1应该是答案。至少让我们检查16。请注意以下&#34; =&#34;应该是一个同余符号(三个条不是两个)。

  

-7mod16 = 9mod16

     

9mod16 = 9mod16

     

25mod16 = 9mod16

您可以检查这是否也适用于因素2,4,8。 (对于所有这些因素,您应该获得1mod8 => 1mod4 => 1mod2。)

收转

如果您必须在代码中找到这些因素,您可能会对factoring algorithms中的一个感兴趣,以查找G的所有因子大于1.挑选最优化的因素可能取决于您的数据

因此,它实际上是您可能需要的算法组合。我上面展示的内容可能会稍微快一些,但基本算法现在应该是平易近人的。

答案 1 :(得分:0)

#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;
}

答案 2 :(得分:0)

这是我解决该问题的代码

n = int(input("how many numbers to guess? (normally 4)"))
att = int(input("how many attempts? (normally 10)"))
count = 0
pul = {}  # here're your previous lists, currently empty
while count < att:
    ul = [int(input()) for i in range(n)]
    pul[count] = ul  # you can use more flexible key value, as you mentioned
    count = count + 1
    # if you need to replay lists - you just use your "pul" dict
for i in range(count):
    print(f'your № {i} list was {pul.get(i)}')