在O(n)时间内在数组中找到可分的和对

时间:2016-07-15 13:06:28

标签: python algorithm bucket mod

您将获得一组n整数a0, a1, .. an和一个正整数k。查找并打印(i,j)对的数量i+j,其中k可被i+j % k == 0整除(即O(n))。此问题来自here

我们需要1 3 2 6 4 5 9 and k = 3时间的解决方案。

解释是我们可以通过根据mod k将元素分成桶来实现。例如,您有以下元素:mod 3 == 0 : 3 6 9 mod 3 == 1 : 1 4 mod 3 == 2 : 2 5

(3, 6) (3, 9) (6, 9) ( all items in the 0th bucket be paired)

然后,据说:

  

现在,您可以像这样制作对:具有mod 3 == 0的元素将匹配   元素与(3 - 0)mod k = 0,所以mod 3中的其他元素   == 0列表,如下:   (3,6)(3,9)(6,9)

此外:

  

将有n *(n - 1)/ 2个这样的对,其中n是长度   列表,因为列表是相同的,我!= j。 mod 3 ==的元素   1将匹配元素与(3 - 1)mod k = 2,所以元素在   mod 3 == 2 list,如下:(1,2)(1,5)(4,2)(4,5)

(a + b)% k = 0 = a % k + b % k开始CustomLoggingFilter.java是有道理的。

不清楚的是如何通过第1(mod 3 == 1)和第2(mod 3 == 2)桶中的元素组合生成其他对,为什么会有n *(n - 1)/ 2对。 还有其他(更好)的方法吗?

这个问题适用于Math Stackexchange,在发布问题之前我不知道它存在。

3 个答案:

答案 0 :(得分:2)

我翻译C代码......

using namespace std;
int main(){

   int n;
   int k;
   cin >> n >> k;
   int a[n];
   int m[k];
   for(int i=0; i<k; i++)
       m[i]=0;
    for(int i = 0; i < n; i++){
       cin >> a[i];
        m[a[i]%k]++;
    }
    int sum=0;
    sum+=(m[0]*(m[0]-1))/2;
     for(int i=1; i<=k/2 && i!=k-i; i++){
         sum+=m[i]*m[k-i];
     }
    if(k%2==0)
        sum+=(m[k/2]*(m[k/2]-1))/2;
    cout<<sum;
    return 0;
}

进入Python:

def divisible_sum_pairs(n, k, a_list):
    m = [0] * len(a_list)
    for a in a_list:
        m[a % k] += 1

    sum = int(m[0] * (m[0] - 1) / 2)
    for i in range(1, int(k / 2) + 1):
        if i != k - 1:
            sum += m[i] * m[k - i]
    if k % 2 == 0:
        sum += m[int(k / 2)] * (m[int(k / 2)] - 1) / 2

    return sum

使用:

print(divisible_sum_pairs(6, 3, [1,  3,  2,  6,  1,  2]))

你得到5

答案 1 :(得分:1)

您有n * (n - 1) / 2对,因为每个人(n)都可以与其他人配对(n-1);但由于顺序无关紧要,我们避免将镜像对除以2。

当分子被求和时,对相同商的余数也求和,但提醒不能超过商。 3分组中3的提示实际上是对0的提醒。

答案非常聪明,你可以通过低级优化让它快几个百分点;例如,实现一个专用的模块3,而不是依赖%的通用算法;但是你不能真正击败O(n),因为你需要至少扫描一次每个元素,而且解决方案已经做得不多了。 (事实上​​,当你被要求结果时,在我看来你不能仅仅因为O(n^2)而不能...... {/ p>

这些问题都与python无关。您知道有math.stackexchange.com吗?

答案 2 :(得分:0)

对于大的K值,此解决方案适用于我。 对于较小的值,Laurent的解决方案更好。

def numPairsDivisibleByK(arr,k):     频率= [对于范围(k)中的i为0]     为我在arr中:         freq [i%k] + = 1

!function refresh () {
  document.getElementById("test").innerHTML = Date.now()
  setTimeout(refresh, 5000)
}()

print numPairsDivisibleByK([30,20,150,100,40],60)