【问题标题】:Finding EVEN number of times repeating integer in an array where rest of the integers repeat ODD number of times在数组中查找重复整数的偶数次,其中其余整数重复奇数次
【发布时间】:2011-11-05 18:53:33
【问题描述】:

Given 是一个整数数组。数组中的每个数字出现奇数次,但只有 1 个数字出现偶数次。找到那个号码。

以下是我在 stackoverflow 上阅读的不起作用的解决方案。我找不到该解决方案的链接,我想知道是否有人可以帮助我理解为什么这个解决方案不正确,除非我在下面做错了什么。

我们首先对数组中的所有元素进行异或。让我们称之为aWithOutDuplicate,它包含除了重复元素之外的所有奇数元素。然后我们对所有元素进行 OR。让我们称它为aAllUnique,它应该包含所有独特的元素。异或 aWithOutDuplicateaAllUnique 应该会吐出重复的元素。

    int arr[] = {1,2,3,4,5,6,7,8,4,9};
    int aWithOutDuplicate = 0;
    int aAllUnique = 0;

    for(int i=0;i<arr.length;i++) {
      aWithOutDuplicate ^= arr[i];
      aAllUnique |= arr[i];
    }

   cout << (aWithOutDuplicate ^ aAllUnique);

更新: 我想知道这个问题是否可以在 O(n) 时间和 O(1) 空间复杂度内解决。

【问题讨论】:

  • 你错了。 {1,2,3,5,6,7,8,9}重复。 {4} 重复一次。一个是奇数。或者您的意思是:“找出出现偶数次的数字”?
  • 为了简单起见,我举了这个例子。当我说重复时,我的意思是该数字的出现次数。考虑到这个定义,只有 4 发生偶数次(2 次),其余奇数次(示例中为 1 次)。
  • 我认为 wildplasser 的意思是重复一个数字会使所有出现在集合中彼此相邻出现。然而,我不认为“重复”这个词的定义需要这样做。

标签: algorithm


【解决方案1】:

如果数组元素在大小为“n”的数组的 [1,n-1] 范围内,则此 O(n), O(1) 空间解决方案有效 . [将适用于 [0,n-1] 并进行以下提到的一些调整]

  • 扫描数组并执行以下操作

    for(i=0; i < n; i++) 
      A[A[i]]=A[A[i]]*(-1)
    
  • 所有奇数出现的数组元素在扫描结束时将具有负值。偶数出现的元素将具有正值。

一些调整: 如果数组范围从 [0,n-1] 开始,则可以有一个特殊情况 '0' 在第一次通过时将 '0' 替换为特殊字符(而不是否定)。您必须在第二遍期间将特殊字符恢复为“0”,依此类推。

【讨论】:

  • [1, n-1] 限制很烦人。但这真的很聪明,我找不到它的错误。 +1。
  • 为什么是常数空间?您需要内存中的输入数组才能使其工作。
【解决方案2】:

这种方法不起作用,因为没有办法区分出现偶数次的数字和根本不出现的数字。考虑这个 4 位示例:

5:  1 0 1
10: 0 1 0 1
-----------
    1 1 1 1 <- both or and xor.

现在,将任意数字(0xf | x == 0xf 用于 x 的所有 4 位值。 xor 将保持不变,因为 0xf ^ x ^ x == 0xf 对于 x 的所有值。因此,您的方法的反例可能是,例如{5, 10, 1, 1}

【讨论】:

    【解决方案3】:

    假设你有一个数组:a, b, a, b, a, c 所以输出应该是b。 我将尝试解释为什么您的算法是错误的。当您应用 OR 运算时,您假设您将获得唯一的数字。是的,当然,一个 |一个 | a == a,但是通过执行以下操作可以获得什么值:a |乙 | c == ? (可能所有位都将设置为 1,具体取决于 a、b、c) 这和做异或不一样。

    【讨论】:

      【解决方案4】:

      在下面的代码中,我发现了重复偶数次的数字,遵循蛮力方法而不使用标准库函数映射:

      //! Print integers occurring an even number of times in array a.
      
      #include <iostream>
      
      int main() {
          int arr[] = { 9, 12, 23, 10, 12, 12, 15, 23, 14, 12, 15 };
          int n = sizeof(arr) / sizeof(arr[0]);
          int b[n], count = 0, c[100];
      
          for (int i = 0; i < n; i++) {
              for (int j = 0; j < n; j++)
                  if (arr[j] == arr[i])
                      b[i] = ++count;
              count = 0;
          }
          for (int i = 0; i < n; i++)
              c[arr[i]] = 0;
          for (int i = 0; i < n; i++) {
              if (c[arr[i]] == 1)
                  continue;
              if (b[i] % 2 == 0)
                  std::cout << arr[i] << std::endl;
              c[arr[i]]++;
          }
          return 0;
      }
      

      【讨论】:

      • 方法的描述看起来很中肯。 (我希望演示文稿更好,如果它 1)包含 cmets everything non-obvious 是为了 2)更常规地缩进:“全局事物”(如 main())在左边缘, 每层 8(或 4)个空格 3)节省了垂直空间:在不需要的地方没有大括号,在自己的一行中打开大括号 not。)不要习惯性地using namespace std;
      • 感谢您的评论。能否请教如何在 stackoverflow 上写出正确的答案?因为我现在是这方面的初学者...
      • (:你不可能知道你在问什么;) 其中一部分有一个准备好的答案:How do I ask a good question?。还有更详细的——让我插入一个Question Checklist。经验法则:您的帖子将被阅读 多次 次 - 应以书面形式尽职尽责(例如,使用拼写检查器、在需要的地方大写、在标点符号 之后使用空格)。当 cmets 要求提供更多信息或澄清时,请编辑您的帖子而不是重新评论。
      • 感谢您的编辑...我知道如何在堆栈溢出时编写代码...并会在编写进一步答案时遵循您的建议...再次感谢..跨度>
      • (刚刚检查并注意到一个错误:in array a 应该读为in array arr(或in array &lt;code&gt;arr&lt;/code&gt;,甚至)。太糟糕了,我的 IDE 没有提醒我这一点,即使它 确实重命名时处理 cmets。更糟糕的是,我没有进行尽职调查……)
      猜你喜欢
      • 1970-01-01
      • 2019-07-03
      • 2020-05-26
      • 2018-07-28
      • 1970-01-01
      • 1970-01-01
      • 2011-01-30
      • 1970-01-01
      • 2022-01-21
      相关资源
      最近更新 更多