【问题标题】:Numbers of common distinct difference共同显着差异数
【发布时间】:2020-10-11 07:07:07
【问题描述】:

给定两个数组 A 和 B。任务找出共同不同的数量(两个数组中元素的差异)。 示例:

A=[3,6,8]
B=[1,6,10]

so we get differenceSet for A
differenceSetA=[abs(3-6),abs(6-8),abs(8-3)]=[3,5,2]
similiarly
differenceSetB=[abs(1-6),abs(1-10),abs(6-10)]=[5,9,4]

Number of common elements=Intersection :{differenceSetA,differenceSetB}={5}
Answer= 1

我的方法 O(N^2)

int commonDifference(vector<int> A,vector<int> B){
    int n=A.size();
    int m=B.size();
    unordered_set<int> differenceSetA;
    unordered_set<int> differenceSetB;
    for(int i=0;i<n;i++){
        for(int j=i+1;j<n;j++){
            differenceSetA.insert(abs(A[i]-A[j]));
        }
    }
    for(int i=0;i<m;i++){
        for(int j=i+1;j<m;j++){
            differenceSetB.insert(abs(B[i]-B[j]));
        }
    }
    int count=0;
    for(auto &it:differenceSetA){
        if(differenceSetB.find(it)!=differenceSetB.end()){
            count++;
        }
    }
    return count;
    
}

请提供优化 O(N log N) 方法的建议

【问题讨论】:

  • 对于给定的数组,您可以在 O(n logn) 中找到差异集:stackoverflow.com/questions/64220374/…
  • @Damien - 请添加包含此内容的答案,然后添加一些逻辑以从中找到共同值。因此,如果他愿意,OP 可以批准和投票
  • 我忘了提到,如果输入值的范围不是太大,这种方法会很有效。算法是(n log n),但是这里n是取值范围,不是输入数组的大小
  • @Damien,我在实施这种方法时遇到了困难。你能帮帮我吗?
  • 我会尝试发布答案,并附上一些细节。数据范围是多少?

标签: c++ algorithm data-structures set c++17


【解决方案1】:

如果 n 是输入数组的最大范围,则可以在 O(n logn) 中获得给定数组的所有差异的集合,如此 SO 帖子中所述:find all differences in a array

以下是对该方法的简要回顾,以及一些额外的实际实现细节:

  1. 创建一个长度为2*n = 2*range = 2*(Vmax - Vmin + 1)的数组Posi,其中索引与输入元素匹配的元素设置为1,其他元素设置为0。这可以在O(m)中创建,其中@987654324 @ 是数组的大小。
    例如,给定大小为m 的输入数组[1,4,5],我们创建一个数组[1,0,0,1,1]。
Initialisation: Posi[i] = 0 for all i (i = 0 to 2*n)
Posi[A[i] - Vmin] = 1 (i = 0 to m)
  1. 计算数组Posi[]的自相关函数。这可以通过三个子步骤经典地执行

2.1 计算Posi[]array的FFT(大小2*n):Y[] = FFT(Posi)

2.2 计算结果的平方幅值:Y2[k] = Y[k] * conj([Y[k])

2.3 计算结果的逆FFTDiff[] = IFFT(Y2[])`

这里有几个细节值得一提:

  • 之所以选择大小2*n,而不是大小n,如果是d 是有效差异,那么-d 也是有效差异。与负差异对应的结果可在位置i &gt;= n 获得
  • 如果您发现使用大小为 2 的幂的 FFT 更容易执行,则可以将大小 2*n 替换为值 n2k = 2^k,替换为 n2k &gt;= 2*n
  1. 非空差异对应数组Diff[]中的非空值:
`d` is a difference if `Diff[d] > 0`

另一个重要的细节是使用了经典的 FFT(浮点计算),然后您会遇到很少的错误。考虑到这一点,重要的是用实部的整数舍入值替换 IFFT 输出Diff[]

所有这些都只涉及一个数组。由于您要计算共同差异的数量,因此您必须:

  • 计算Diff_A[]Diff_B[] 的数组AB,然后:
count = 0;
if (Diff_A[d] != 0) and (Diff_B[d] != 0) then count++;

一点奖励

为了避免对上述帖子的抄袭,这里是关于在FFT的帮助下获取一组差异的方法的附加说明。

输入数组A = {3, 6, 8}在数学上可以用以下z变换表示:

 A(z) = z^3 + z^6 + z^8 
 

那么差分数组对应的z变换等于多项式积:

D(z) = A(z) * A(z*) = (z^3 + z^6 + z^8) (z^(-3) + z^(-6) + z^(-8)) 
= z^(-5) + z^(-3) + z^(-2) + 3 + z^2 + z^3 + z^5 

然后,我们可以注意到A(z) 等于序列[0 0 0 1 0 0 1 0 1] 的大小为 N 的 FFT:

z = exp (-i * 2 PI/ N), with i = sqrt(-1)

请注意,这里我们考虑的是 C 中的经典 FFT,即复数域。

当然可以在 Galois 域中执行计算,然后不会出现舍入错误,例如为大量数字实现“经典”乘法(z = 10)。这在这里似乎过于熟练了。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-07-28
    • 2023-01-31
    • 2015-01-09
    • 1970-01-01
    • 2010-10-19
    • 2010-10-29
    • 2020-10-03
    • 2013-01-19
    相关资源
    最近更新 更多