【问题标题】:Suggest an Efficient Algorithm建议一个有效的算法
【发布时间】:2010-11-18 11:11:49
【问题描述】:

给定一个大小为 100000 的数组 arr,每个元素 0 <= arr[i] < 100。 (未排序,包含重复)

找出有多少个三元组(i,j,k) 存在这样arr[i] ^ arr[j] ^ arr[k] == 0 注意^ 是 Xor 运算符。还有0 <= i <= j <= k <= 100000

我觉得我必须计算频率并使用频率进行一些计算,但我似乎无法开始。

欢迎任何比显而易见的O(n^3) 更好的算法。 :)

这不是家庭作业。 :)

【问题讨论】:

  • 只是好奇....如果不是作业,那是什么?
  • 面试题呢?如果没有,你能解释一下这将用于什么 - 我现在想不出一个应用程序吗?
  • 这是 Project Euler 310 :),成功解决了一半的问题...顺便说一句,我们所说的 O(n^3) 正在运行 :)
  • 从 0 到 99 的三个值的组合只有 100000 种。你的数组有 100000 长。也许巧合,即使不是,我也不确定它有什么帮助。此外,条件等价于 arr[i] ^ arr[j] == arr[k]。也看不出这有什么帮助:)
  • @Paul,实际上是 74...不是 100...我只是想让数字保持四舍五入。

标签: arrays algorithm xor


【解决方案1】:

我认为关键是您不需要识别 i,j,k,只需数一下。

初始化一个大小为 100 的数组

通过 arr 循环,计算每个值有多少 - O(n)

循环遍历小数组的非零元素,找出满足条件的三元组 - 假设所涉及的三个数字的计数是 A、B、C - 原始 arr 中的组合数是 (A+ B+C)/!A!B!C! - 100**3 次操作,但假设 100 是一个固定值,这仍然是 O(1)。

所以,O(n)。

【讨论】:

  • 问题是:i <= j <= k 指的是索引而不是整数本身。因此,我担心这是错误的。
  • 不,我不这么认为。而且您似乎在评论其他问题,因为我不依赖 i
  • 啊终于明白了,通过使用组合,您可以确保在不依赖索引顺序的情况下不会重复,我被这种情况分心了,看不出它的意思确保。
【解决方案2】:

如果可行,可能的 O(n^2) 解决方案:维护变量 count 和两个数组 single[100]pair[100]。迭代arr,并为每个元素的值n

  • 更新count:count += pair[n]
  • 更新pair:迭代数组single,并为索引x和值s != 0的每个元素做pair[s^n] += single[x]
  • 更新single:single[n]++

最终count 持有结果。

【讨论】:

    【解决方案3】:

    可能的 O(100 * n) = O(n) 解。 它解决了问题 i A = B,所以

    long long calcTripletsCount( const vector<int>& sourceArray )
    {
      long long res = 0;
      vector<int> count(128);
      vector<int> countPairs(128);
      for(int i = 0; i < sourceArray.size(); i++)
      {
        count[sourceArray[i]]++; // count[t] contain count of element t in (sourceArray[0]..sourceArray[i]) 
        for(int j = 0; j < count.size(); j++)
          countPairs[j ^ sourceArray[i]] += count[j]; // countPairs[t] contain count of pairs p1, p2 (p1 <= p2 for keeping order) where t = sourceArray[i] ^ sourceArray[j]
        res += countPairs[sourceArray[i]]; // a ^ b ^ c = 0 if a ^ b = c, we add count of pairs (p1, p2) where sourceArray[p1] ^ sourceArray[p2] = sourceArray[i]. it easy to see that we keep order(p1 <= p2 <= i)
      }  
      return res;
    }
    

    对不起我的英语不好......

    【讨论】:

    • 我认为你的嵌套循环使它成为 O(n^2)。
    • count.size() = 128。它可以在不到 1 秒的时间内处理 100 000 个元素。
    • 哦,我用这个算法解决了 Project Euler 310 问题:)
    • 你的解决方案和我的差不多,只是更新的顺序不同。我更新计数,然后对数组,然后是单个数组。您更新计数数组(我的单个),然后是 countPairs,然后是 res(我的计数)。我们的结果会有所不同。恕我直言,我的更新顺序是正确的。
    • 您可以在小测试中使用 brutforce 算法进行检查。假设存在非严格不等式。在您的算法中,您计算​​三元组,其中 i
    【解决方案4】:

    我有一个(简单的)O(n^2 log n) 解决方案,它考虑到 i、j 和 k 指的是索引,而不是整数。

    简单的第一遍允许我们构建一个包含 100 个值的数组 A:值 -> 索引列表,我们将列表排序以备后用。 O(n log n)

    对于每对 i,j 使得 i = j。 O(n^2 log n)

    我找不到任何方法来利用排序/计数算法,因为它们消除了索引要求。

    【讨论】:

      【解决方案5】:
      Sort the array, keeping a map of new indices to originals. O(nlgn)
      Loop over i,j:i<j. O(n^2)
        Calculate x = arr[i] ^ arr[j]
        Since x ^ arr[k] == 0, arr[k] = x, so binary search k>j for x. O(lgn)
        For all found k, print mapped i,j,k
      

      O(n^2 lgn)

      【讨论】:

      • 我认为您需要将 k 限制为大于 j,因此只需搜索 if x >= x[j]。
      • 如果对数组进行排序,就会失去原数组中ijk的含义。因此,您的计数可能完全不同。
      • @Matthieu:是的,你需要映射 i,j,k。已编辑。
      【解决方案6】:

      按照 Paul 的建议,从 1 到 100 之间的每个数字出现的频率计数开始。这会产生一个长度为 100 的数组 freq[]。

      接下来,不是从该数组循环遍历三元组 A、B、C 并测试条件 A^B^C=0, 循环对 A,B 与 A

      Sum+=freq[A]*freq[B]*freq[C]
      

      频率计数的工作量为 O(n),加上 A

      由于三个不同数字 A、B、C 的每一个三元组都必须以某种顺序出现,因此每个这样的三元组都恰好出现一次。接下来,您必须寻找两个数字相等的三元组。但是,如果两个数相等且其中三个的异或为 0,则第三个数必须为零。所以这相当于在频率计数数组上对 B 进行二次线性搜索,计算 (A=0, B=C

      希望这会有所帮助!

      【讨论】:

      • 这填写了我的答案的手波位:) 谢谢
      • 您实际上需要遍历数组,因为 i、j 和 k 表示的不是整数而是索引位置。
      • 但是,计算是在 arr[i] 等上,而不是 i,所以这无关紧要。鉴于我们不需要 i、j 和 k 的值,并且数组是无序的,这意味着值的任何排序都会给出相同的答案。特别是,对元素进行排序的顺序与其他顺序一样有效。这意味着 100 个计数的数组包含与完整的“arr”数组相同的信息,用于本问题的目的。
      • 请注意,频率计数数组的索引 (A, B, C) 不对应于原始数组 arr[i] 的索引,而是存储在其中的值。根据 A、B、C 是否不同来划分案例并不容易转化为 i、j、k 的条件。
      猜你喜欢
      • 1970-01-01
      • 2012-08-14
      • 1970-01-01
      • 2012-03-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多