【问题标题】:Finding max occurence of element, array syntax [closed]查找元素的最大出现次数,数组语法[关闭]
【发布时间】:2014-11-16 01:24:30
【问题描述】:

以下代码是用于搜索数组中元素的最大出现次数的算法。此解决方案假定元素的范围为 0 到 n-1。

void MaxRepetitions( int A[], int n ) {

int i=0; max=0, maxIndex;

for(i=0, i<n, i++) 
    A[A[i]%n] +=n;

for( i=0, i<n, i++)

    if (A[i]/n > max) { 
       max = A[i]/n;
       maxIndex=i;

}

return maxIndex;
}

A[A[i]%n] +=n; 是如何扩展的?

A[A[i]%n] = A[A[i]%n] + n 正确吗?

--

编辑

例如 A = [2, 4, 7, 5, 4, 11],其中 n=6

A[0]%n = 2
A[1]%n = 4
A[2]%n = 1
A[3]%n = 5
A[4]%n = 4
A[5]%n = 5

在这个循环之后:

for(i=0, i<n, i++) 
    A[A[i]%n] = A[A[i]%n] + n;

Iteration 1: 

A[A[0]%n] = A[A[0]%n] + 6   --> A[2] = A[2] + 6  --> A[2] = 13

The array is now: A = [2, 4, 13, 5, 4, 11]

Iteration 2:

A[A[1]%n] = A[A[1]%n] + 6   --> A[4] = A[4] + 6  --> A[4] = 10

The array is now: A = [2, 4, 13, 5, 10, 11]


Iteration 3:

A[A[2]%n] = A[A[2]%n] + 6   --> A[1] = A[1] + 6  --> A[1] = 10

The array is now: A = [2, 10, 13, 5, 10, 11]

Iteration 4:

A[A[3]%n] = A[A[3]%n] + 6   --> A[5] = A[5] + 6  --> A[5] = 17

The array is now: A = [2, 10, 13, 5, 10, 17]

Iteration 5:

A[4] now is 10

A[A[4]%n] = A[A[4]%n] + 6   --> A[4] = A[4] + 6  --> A[4] = 16

The array is now: A = [2, 10, 13, 5, 16, 17]

Iteration 6:

A[5] now is 17

A[A[5]%n] = A[A[5]%n] + 6   --> A[5] = A[5] + 6  --> A[5] = 23

数组现在是:A = [2, 10, 13, 5, 16, 23]

现在,一旦第二个循环运行,每个元素的 A[i]/n 为:A [0, 1, 2, 0, 2, 3 ]

看起来这个算法会选择 11 作为出现次数最多的元素,这是不正确的。有什么帮助吗?

【问题讨论】:

  • How is A[A[i]%n] +=n; expanded??是的,它是A[A[i]%n] = A[A[i]%n] + n;
  • 好的,我现在有一个后续问题待处理
  • 你不是说一个元素的范围是0到n-1(不是n到n-1)吗?如果任何元素为负数或大于 n-1,此代码将无法正常工作。
  • 至少maxIndex = i
  • 那么您的问题是+= 运算符是如何工作的?请将您的问题简化为一个最小示例,并正确格式化。

标签: c algorithm search


【解决方案1】:

正如其他人所说,&lt;anything&gt; += &lt;value&gt; 等价于 &lt;anything&gt; = &lt;anything&gt; + &lt;value&gt;,只是 &lt;anything&gt; 只计算一次。

您对算法运行的分析是正确的,但问题是输入违反了所有元素都在 0 和 n-1 之间的规定约束。实际上,由于 11 % 6 = 5,算法产生的答案并非完全错误(模 6,值 5 与值 4 出现的次数相同)。但是,还有一个问题是,由于违反了输入约束,因此计数已关闭,原因我在下面的评论中进行了解释。

了解其工作原理的最佳方法是查看另一种算法,虽然看起来完全不同,但实际上是相同的。这个另一种算法是:

  1. 分配一个单独的数组C[n]。 (C 表示“计数”。)
  2. 遍历A 中的每个元素A[i] 并设置C[A[i]] += 1。不难看出,由于每个A[i]都介于0和n-1之间,当这一步完成时,任何jC[j]将是所有j值出现的次数A[i]
  3. 因此,C 的最大元素的位置A 中出现频率最高的值(可以任意解决平局)。只需遍历C 即可找到发生这种情况的位置并返回结果。

现在您发布的算法正是如此,但巧妙地利用了两个事实,这两个事实都依赖于 A[i] 的原始值在 0n-1 之间:

  1. 无论n 被添加到A[i] 多少次,A[i]%n 的值都将完全等于A[i]原始值。
  2. A[i]/n 的值将完全等于n 被添加到A[i] 的次数,而与A[i] 的原始值无关。

因此,如果我们通过添加 n 而不是 1 来修改第二个算法,并按照您发布的算法中所做的那样使用 %n/n,我们可以让 A 为两者提供原始值并用于计数。

【讨论】:

  • 感谢您的回复。两点:1.我相信我最后一次迭代是正确的,它就在代码块下面。 2.函数返回5,但是如果你看原始数组,A[],数字5只出现了一次,而数字4出现了两次。
  • @martinap - 抱歉,我早该注意到并对此发表评论。您的原始数组违反了元素都在 0 和 n-1 之间的输入约束。具体来说,A[2] 是 7,A[5] 是 11。实际上,这就像将 C 数组初始化为全零,除了索引 2 和 5 的计数为 1。然后,5 增加两次:一次为 @ 987654356@ 和A[5]。另请注意,2 的计数太高是因为 A[2] &gt; 5,而 1 的计数太高是因为 A[2] 被计为另一个 1。
  • @martinap - 我更新了我的答案来解决这个问题。
【解决方案2】:

A[A[i]%n] +=n

A[i]           : value contained in array A at position i
A[i]%n         : remainder of dividing this value by n (used to not allow this index go beyond the size of A
A[A[i]%n]      : the value contained in that new position
A[A[i]%n] += n : add n to this value

数值示例

A[3] = {7, 10, 24}
n = 3

i = 0
A[A[0]%3] = A[7%3] // 7 = 2*3 + 1
          = A[1]
          = 10
add 3 ==> A[1] = 13

i = 1
A[A[1]%3] = A[13%3] // 13 = 4*3 +1
          = A[1]
          = 13
add 3 ==> A[1] = 16

i = 2
A[A[2]%3] = A[24%3] // 24 = 8*3 + 0
          = A[1]
          = 7
add 3 ==> A[1] = 10

【讨论】:

    【解决方案3】:

    这个:

    A[A[i]%n] +=n
    

    扩展为等价于:

    A[A[i]%n] = A[A[i]%n] + n
    

    除了副作用只评估一次。换句话说,如果左表达式使用了带有副作用的运算符,如++--,那么这些副作用只会出现一次,这与你实际写出整个x = x + y 的情况相反。表达式,其中x 中的副作用将被计算两次。

    【讨论】:

      猜你喜欢
      • 2011-04-17
      • 2021-12-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-05-21
      • 1970-01-01
      相关资源
      最近更新 更多