【问题标题】:Compare two integer arrays with same length比较两个长度相同的整数数组
【发布时间】:2010-03-08 15:12:50
【问题描述】:

[描述] 给定两个长度相同的整数数组。设计一个算法来判断它们是否相同。 “相同”的定义是,如果这两个数组按排序顺序排列,则对应位置的元素应该相同。

[Example]
<1 2 3 4>  = <3 1 2 4>
<1 2 3 4> != <3 4 1 1>

[限制]该算法需要恒定的额外空间,以及O(n)的运行时间。

【问题讨论】:

  • 已标记为面试问题。
  • 嗯...也许想骗你,因为显而易见的方法 O(1) 空间和 O(n) 时间... 哪里有问题?
  • @mjv:如果你有 O(n) 的解决方案,请告诉。
  • 这些数组是只读的,还是我们可以更改它们?
  • 这个问题完全取决于整数是否有界......如果整数在两边都有界,则计算出现次数的数组具有恒定的空间要求。如果不是,那么问题很可能无法解决。

标签: arrays algorithm


【解决方案1】:

(对于面试问题来说可能太复杂了。)

(可以先用O(N)时间检查min、max、sum、sumsq等是否相等。)

使用no-extra-space radix sort 对两个数组进行就地排序。 O(N) 时间复杂度,O(1) 空间。

然后使用通常的算法比较它们。 O(N) 时间复杂度,O(1) 空间。

(如果数组的 (max − min) 是 O(Nk) 且具有有限 k。)

【讨论】:

  • 仅当它们是有界整数时。
  • 鉴于我们在这里谈论的是计算机,它们总是有界的。诚然,占用(比如说)16 GB 的整数会有一个非常大的上限,但它仍然是一个界限。
  • 按照这种逻辑,您可以说天真的“哈希表”解决方案是正确的,因为您只需将哈希表设置为一个恒定但巨大的大小。
  • @Larry:如果你看看我的回答,我确实是这么说的。
  • 按照这个逻辑,在有界整数上,创建一个大小为 MAX_INT 的哈希表。这是一个常数,我敢肯定! ;P
【解决方案2】:

您可以尝试一种概率方法 - 将数组转换为一些大基数 B 和一些素数 P 中的数字,例如 sum B^a_i for all i mod some big-ish @987654326 @。如果它们都得出相同的数字,请再次尝试尽可能多的素数。如果任何尝试都是错误的,那么它们就是不正确的。如果他们通过了足够多的挑战,那么他们是平等的,很有可能

B > N, P > 最大数有一个简单的证明。所以一定有一个无法应对的挑战。这实际上是确定性方法,尽管复杂性分析可能更困难,这取决于人们如何根据输入的大小(而不仅仅是元素的数量)来看待复杂性。

【讨论】:

  • 总是有碰撞的机会。
  • 我不相信这是 100%,但是嘿,如果你正在接受面试,你可能会做得更糟。
  • @Timmy,这有时肯定会发生冲突,因为不同数组的数量远远大于不同整数的数量。跨度>
  • 为什么说“高概率”而不是计算呢?无法克服的理想概率是 (1 - 1/MAX_INT)。
  • 高概率是概率算法中使用的实际术语 - algorithmist.com/index.php/With_high_probability
【解决方案3】:

我声称:除非指定输入范围,否则不可能在即时额外空间和 O(n) 运行时间中求解。

我会很高兴被证明是错误的,这样我就可以学到新的东西。

【讨论】:

  • 你能证明这个问题的下界吗?
  • 我同意如果没有整数范围,这个问题在 O(n) 时间和恒定空间内是无法解决的。
【解决方案4】:
  1. 将第一个数组中的所有元素插入哈希表中
  2. 尝试将第二个数组中的所有元素插入到同一个哈希表中 - 每个插入元素都应该已经存在

好的,这不是固定的额外空间,而是我目前能想到的最好的:-)。是否对问题施加了任何其他限制,例如可能包含在数组中的最大整数?

【讨论】:

  • "将第一个数组中的所有元素插入哈希表" 您需要 O(n) 内存来分配哈希表,而您只需要 O(1)。
  • @Pavel:不,你不需要 O(n)。 O(n) 将是,如果数组的大小加倍(例如),您会期望哈希表的大小也(大约)加倍。根本不是这样的。
  • @Pavel 在最坏的情况下我需要 O(n),我在帖子中说过。我知道这只是部分解决方案,但也许可以改进。
  • @Jerry, @pajton,在 any 的情况下,您需要 O(n),前提是数组中的所有值都不同。当您将元素添加到表中时,您必须存储您添加的确切值(以供将来比较)。它将是列表中的新项目(对于桶列表),或者要求至少有 n 个桶(开放寻址)。这些都是 O(n)。
  • @pajton,不考虑额外空间的成本,您的解决方案仍然是错误的。举个例子:, 你能说它们是一样的吗?
【解决方案5】:

一些答案​​基本上是正确的,即使它们看起来不像。哈希表方法(例如)具有基于所涉及的 type 范围而不是数组中元素数量的上限。至少根据大多数定义,这使得(上限)空间成为一个常数,尽管该常数可能非常大。

理论上,您可以将其从上限更改为真正的恒定空间量。举例来说,如果您使用 C 或 C++,并且它是 char 的数组,您可以使用类似:

size_t counts[UCHAR_MAX];

由于 UCHAR_MAX 是一个常数,所以数组使用的空间量也是一个常数。

编辑:我想记录一下,所涉及的项目的范围/大小的界限隐含在算法复杂性的几乎所有描述中。举个例子,我们都“知道”快速排序是一个 O(N log N) 算法。然而,只有当我们假设比较和交换被排序的项目需要恒定时间时,这才是正确的,这只有在我们限制范围时才会正确。如果涉及的项目范围足够大,我们不能再将比较或交换视为花费恒定时间,那么它的复杂性将类似于 O(N log N log R),如果 R 是范围,所以@987654323 @ 近似表示一个项目所需的位数。

【讨论】:

  • 我不同意你的看法。这样,所有在 O(n) 中运行的算法都是常数,因为如果你有一个大小为 n 的数组,但你知道 n 表示为整数,它的元素少于 MAX_INT,因此是常数。
  • 这就是使这些面试问题有时具有学术性的原因。 O(N) 不惜一切代价是不切实际的!
  • @pajton:没有可比性。您正在谈论正在处理的数组大小的限制。我说的是对数组中项目范围的限制,无论其大小如何。
  • @Pajton 考虑一下 KennyTM 给出的答案。它链接到 O(n) 基数排序,该排序仅在整数范围有限时才有效。否则排序不能在 O(n) 中工作
  • 我明白你的意思。但是作者并没有说数组中元素的界限,所以如果你假设它们的范围是有界限的,那么它与长度界限是一样的。
【解决方案6】:

这是一个技巧问题吗?如果作者假设整数在给定范围内(2^32 等),那么“额外的常数空间”可能只是一个大小为 2^32 的数组,您可以在其中计算两个列表中出现的次数。

如果整数是无范围的,则无法做到。

【讨论】:

    【解决方案7】:

    您可以将每个元素添加到 hashmap 中,规则如下:数组 A 是加法器,数组 B 是删除器。从 Array A 插入时,如果 key 不存在,则插入值为 1。如果 key 存在,则递增 value(保持计数)。移除时,若key存在且大于1,则减1。若key存在且为1,则移除元素。

    使用上述规则遍历数组 A,然后遍历数组 B。如果在移除阶段数组 B 中的任何时候都没有找到元素,则可以立即返回 false。如果 adder 和 remover 都完成后 hashmap 为空,则数组是等价的。

    编辑:哈希表的大小将等于数组中不同值的数量这是否符合常量空间的定义?

    【讨论】:

    • 不,它不等于数组的长度,它等于数组中不同值的个数。
    【解决方案8】:

    我想该解决方案将需要某种既具有关联性又具有可交换性的转换,并保证一组唯一输入的唯一结果。但是我不确定它是否存在。

    【讨论】:

    • 我在想一些类似的事情,例如。证明对于 Z\{0,1} 的子集 A,B 其中 |A| = |B|,那么如果 sum(a_i) = sum(b_i) 和 prod(a_i) = prod(b_i) 在一些排列之后我们必须有 A = B ...困难的部分是证明:P
    • 没错!我尝试使用 sum() 和 prod() 但它在几个输入上失败了,例如: [-10, -10, -10, -1, 9] != [6, -3, 5, -10, - 10] 但它们的总和和乘积是相等的。
    【解决方案9】:
    public static boolean match(int[] array1, int[] array2) {
    
            int x, y = 0;
    
            for(x = 0; x < array1.length; x++) {
                    y = x;
                    while(array1[x] != array2[y]) {
                            if (y + 1 == array1.length)
                                    return false;
                            y++;
                    }
                    int swap = array2[x];
                    array2[x] = array2[y];
                    array2[y] = swap;
            }
    
            return true;
    }
    

    【讨论】:

      【解决方案10】:

      对于每个数组,使用计数排序技术来构建小于或等于特定元素的元素数的计数。然后在每个索引处比较两个构建的辅助数组,如果它们 r 等于数组 r 等于,否则它们 r 不是。计数排序需要 O(n) 并且每个索引处的数组比较再次是 O(n) 所以完全是它的 O(n) 并且所需的空间等于两个数组的大小。这是计数排序http://en.wikipedia.org/wiki/Counting_sort 的链接。

      【讨论】:

      • 所需空间为 O(n)。不会飞。
      • 对不起,我想我跳得早了
      【解决方案11】:

      给定 int 在 -n..+n 范围内,检查净值的简单方法可能如下(伪代码):

      // a & b are the array
      accumulator = 0
      arraysize = size(a)
      for(i=0 ; i < arraysize; ++i) {
        accumulator = accumulator + a[i] - b[i]
        if abs(accumulator) > ((arraysize - i) * n) { return FALSE }
      }
      return (accumulator == 0)
      

      累加器必须能够存储范围 = +- arraysize * n 的整数

      【讨论】:

        【解决方案12】:

        这个怎么样 - 对两个数组中的所有数字进行异或。如果结果为 0,则匹配成功。

        【讨论】:

        • XOR(1, 2, 3) = XOR(2, 4, 6) = 0
        猜你喜欢
        • 2013-04-02
        • 1970-01-01
        • 1970-01-01
        • 2012-02-25
        • 1970-01-01
        • 1970-01-01
        • 2022-12-10
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多