【问题标题】:Array of size n, with one element n/2 times大小为 n 的数组,有一个元素 n/2 次
【发布时间】:2017-10-03 21:24:07
【问题描述】:

给定一个包含 n 个整数的数组,其中一个元素出现超过 n/2 次。我们需要在线性时间和恒定的额外空间中找到该元素。

YAAQ:又一个数组问题。

【问题讨论】:

标签: algorithm


【解决方案1】:

我有一个偷偷摸摸的怀疑它类似于(在 C# 中)

// We don't need an array
public int FindMostFrequentElement(IEnumerable<int> sequence)
{
    // Initial value is irrelevant if sequence is non-empty,
    // but keeps compiler happy.
    int best = 0; 
    int count = 0;

    foreach (int element in sequence)
    {
        if (count == 0)
        {
            best = element;
            count = 1;
        }
        else
        {
            // Vote current choice up or down
            count += (best == element) ? 1 : -1;
        }
    }
    return best;
}

这听起来不太可能,但确实有效。 (Proof as a postscript file,由 Boyer/Moore 提供。)

【讨论】:

  • 酷!它之所以有效,是因为(通过归纳)您正在寻找的元素与给定一个较小的数组所找到的元素相同,其中包含较少数量的其他元素的尾部已被删除。
  • 这应该可以工作,因为最终你必须得到重复的项目,即它应该与 {...random.. ,1,1,1,1,1,1.. } 最坏的情况是 {1,a,1,b,1,c,1,d.. }
  • 嗯,这甚至​​不起作用?试试:int[] wrongwrongwrong = {4, 2, 2, 3, 2, 4, 3, 2, 6, 4};
  • @Blankman:嗯……奇怪。我会考虑修复它。感谢您指出。
  • @Blankman:哦,我已经解决了。在您的示例中,没有元素出现超过 n/2 次。我的实现未验证输入是否与问题描述匹配。
【解决方案2】:

求中位数,在未排序的数组上需要 O(n)。由于超过 n/2 个元素等于相同的值,因此中位数也等于该值。

【讨论】:

    【解决方案3】:
    int findLeader(int n, int* x){
        int leader = x[0], c = 1, i;
        for(i=1; i<n; i++){
            if(c == 0){
                leader = x[i];
                c = 1;
            } else {
                if(x[i] == leader) c++;
                else c--;
            }
        }
    
        if(c == 0) return NULL;
        else {
            c = 0;
            for(i=0; i<n; i++){
                if(x[i] == leader) c++;
            }
            if(c > n/2) return leader;
            else return NULL;
        }
    }
    

    我不是此代码的作者,但这可以解决您的问题。第一部分寻找潜在的领导者,第二部分检查它是否在数组中出现超过 n/2 次。

    【讨论】:

      【解决方案4】:

      您可以按照here[pdf] 的描述进行就地基数排序,这不需要额外的空间和线性时间。然后您可以单次通过计数连续元素并在 count > n/2 处终止。

      【讨论】:

        【解决方案5】:

        这是我最初的想法。

        我尝试保持不变的“一个元素出现超过 n/2 次”,同时减少问题集。

        让我们开始比较 a[i], a[i+1]。如果它们相等,我们比较 a[i+i]、a[i+2]。如果不是,我们从数组中删除 a[i]、a[i+1]。我们重复这个直到 i>=(current size)/2。此时,我们将让“THE”元素占据第一个(当前大小)/2 个位置。 这将保持不变。

        唯一需要注意的是,我们假设数组在一个链表中[因为它给出了 O(n) 复杂度。]

        大家怎么说?

        -bhupi

        【讨论】:

          【解决方案6】:

          怎么样: 随机选择一小部分 K 元素并查找重复项(例如前 4 个、前 8 个等)。如果 K == 4,则没有得到至少 2 个重复项的概率为 1/8。如果 K==8 那么它会低于 1%。如果您发现没有重复,请重复该过程,直到您找到为止。 (假设其他元素更随机分布,这将表现得非常糟糕,例如,数组的 49% =“A”,数组的 51% =“B”)。

          例如:

          findDuplicateCandidate: 
              select a fixed size subset.
              return the most common element in that subset
              if there is no element with more than 1 occurrence repeat.
              if there is more than 1 element with more than 1 occurrence call findDuplicate and choose the element the 2 calls have in common    
          

          这是一个恒定顺序操作(如果数据集还不错),因此请按顺序(N)对数组进行线性扫描以验证。

          【讨论】:

            【解决方案7】:

            我的第一个想法(不充分)是:

            • 对数组进行就地排序
            • 返回中间元素

            但这将是 O(n log n),任何递归解决方案也是如此。

            如果您可以破坏性地修改数组(并且适用各种其他条件),您可以使用它们的计数或其他内容替换元素。你对数组还有什么了解吗,你可以修改它吗?

            编辑将我的答案留给后代,但我认为 Skeet 明白了。

            【讨论】:

              【解决方案8】:

              在php中---请检查是否正确

              function arrLeader( $A ){
              $len = count($A);
              $B = array();
              $val=-1;
              $counts = array_count_values(array); //return array with elements as keys and occurrences of each element as values
              for($i=0;$i<$len;$i++){
                  $val = $A[$i];
                  if(in_array($val,$B,true)){//to avoid looping again and again
                  }else{
                   if($counts[$val]>$len/2){
                    return $val;
                   }
                   array_push($B, $val);//to avoid looping again and again
                  }
               }
               return -1;
              }
              

              【讨论】:

                【解决方案9】:
                int n = A.Length;
                            int[] L = new int[n + 1];
                            L[0] = -1;
                            for (int i = 0; i < n; i++)
                            {
                                L[i + 1] = A[i];
                            }
                            int count = 0;
                            int pos = (n + 1) / 2;
                            int candidate = L[pos];
                            for (int i = 1; i <= n; i++)
                            {
                                if (L[i] == candidate && L[pos++] == candidate)
                                    return candidate;
                            }
                            if (count > pos)
                                return candidate;
                            return (-1);
                

                【讨论】:

                • 欢迎来到 Stack Overflow!感谢您提供此代码 sn-p,它可能会提供一些有限的即时帮助。一个正确的解释would greatly improve 它的长期价值通过展示为什么这是一个很好的解决问题的方法,并将使它对未来有其他类似问题的读者更有用。请edit您的回答添加一些解释,包括您所做的假设。
                猜你喜欢
                • 2022-09-23
                • 2020-11-23
                • 1970-01-01
                • 2014-10-08
                • 2020-08-09
                • 1970-01-01
                • 2018-11-08
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多