检查数组B是否是A的排列

时间:2012-05-17 16:28:03

标签: algorithm permutation

我试图找到一个解决方案,但无法解决这个问题。

我们得到两个未排序的整数数组A和B.我们必须检查数组B是否是A的排列。如何做到这一点。甚至对数字进行异或也不会起作用,因为可能有几个具有相同XOR值的反例不是彼此的排列。

解决方案需要O(n)时间并且空间为O(1)

欢迎任何帮助!! 感谢。

9 个答案:

答案 0 :(得分:11)

问题是理论问题,但你可以在O(n)时间和o(1)空间中进行。分配2个 32 计数器的数组并将它们全部设置为零。这是O(1)步骤,因为数组具有恒定的大小。然后遍历两个数组。对于数组A,递增与读取的整数对应的计数器。对于数组B,递减它们。如果在数组B的迭代期间遇到负计数器值,则停止---数组不是彼此的排列。否则在最后(假设A和B具有相同的大小,一个先决条件)计数器数组全部为零,并且两个数组是彼此的排列。

这是O(1)空间和O(n)时间解决方案。然而,这是不切实际的,但很容易通过作为面试问题的解决方案。至少它应该。

更加模糊的解决方案

  • 使用非确定性计算模型,检查两个数组是否彼此的排列可以在O(1)空间中完成,O( n)通过猜测两个数组上具有不同计数的元素,然后计算两个数组上该元素的实例来计算时间。

  • 随机计算模型中,构造随机交换哈希函数并计算两个数组的哈希值。如果散列值不同,则阵列不是彼此的排列。否则他们可能会。重复多次以使误差概率低于所需阈值。同样在O(1)空间O(n)时间方法,但随机化。

  • parallel 计算模型中,让'n'为输入数组的大小。分配'n'个线程。每个线程i = 1 .. n从第一个数组中读取第i个数;让那是x。然后,同一个线程计算第一个数组中x的出现次数,然后检查第二个数组上的相同计数。每个线程使用O(1)空间和O(n)时间。

  • 将整数数组[a1,...,an]解释为多项式x a1 + x a2 + ... + x an 其中x是自由变量,并且数值检查所获得的两个多项式的等价性。使用浮点算术进行O(1)空间和O(n)时间操作。由于舍入误差并且因为等价的数值检查是概率性的,因此不是精确的方法。或者,将多项式解释为以素数为模的整数,并执行相同的概率检查。

答案 1 :(得分:7)

如果允许我们自由访问大量素数列表,您可以通过利用素因子化的属性来解决这个问题。

对于两个数组,计算每个整数i的Prime [i]的乘积,其中Prime [i]是第i个素数。如果它们是彼此的排列,那么数组的乘积值是相等的。

Prime推算有助于此,原因有两个。

  1. 乘法是可传递的,因此计算产品的操作数的顺序是无关紧要的。 (有人提到这样一个事实,即如果数组被排序,这个问题将是微不足道的。通过乘法,我们隐式排序。)
  2. 素数无损地增加。如果我们得到一个数字,并告诉它只是素数的乘积,我们可以准确计算出哪些素数被输入到它中以及究竟有多少素数。
  3. 示例:

    a = 1,1,3,4
    b = 4,1,3,1
    Product of ith primes in a = 2 * 2 * 5 * 7 = 140
    Product of ith primes in b = 7 * 2 * 5 * 2 = 140
    

    也就是说,我们可能不允许访问素数列表,但这似乎是一个很好的解决方案,所以我想我会发布它。

答案 2 :(得分:5)

我为发布这个作为答案而道歉,因为它应该是对antti.huima答案的评论,但我还没有声誉可以发表评论。

计数器数组的大小似乎是O(log(n)),因为它取决于输入数组中给定值的实例数。

例如,让输入数组A全为1,长度为(2 ^ 32)+ 1.这将需要一个33位大小的计数器进行编码(实际上,它会使数组的大小加倍) ,但让我们坚持理论)。 A的大小加倍(仍为1个值),每个计数器需要65位,依此类推。

这是一个非常挑剔的论点,但这些面试问题往往非常挑剔。

答案 3 :(得分:3)

如果我们不需要就地排序,那么以下方法可能有效:

  1. 创建一个HashMap,Key作为数组元素,Value作为出现次数。 (处理多次出现的相同数字)
  2. 遍历阵列A.
  3. 在HashMap中插入数组元素。
  4. 接下来,遍历数组B.
  5. 在HashMap中搜索B的每个元素。如果对应的值为1,则删除该条目。否则,将值减1。
  6. 如果我们能够处理整个数组B并且当时HashMap为空,则成功。别的失败。
  7. HashMap将使用常量空间,您将只遍历每个数组一次。

    不确定这是否是您要找的。如果我错过了有关空间/时间的任何限制,请告诉我。

答案 4 :(得分:1)

您有两个约束条件:计算O(n),其中n表示A和B以及内存O(1)的总长度。

如果两个系列A,B是彼此的排列,那么也是由A或B的排列产生的系列C.所以问题是将A和B都置换为C_A和C_B系列并进行比较。

一种这样的排列将是排序。有几种排序算法可以在适当的位置使用,因此您可以对A和B进行排序。现在在最好的情况下,Smooth Sort按O(n)计算和O(1)内存复杂度排序,最坏的情况是O(n log n)/ O(1)。

然后每个元素的比较发生在O(n),但由于在O符号O(2 * n)= O(n)中,使用平滑排序和比较将得到O(n)/ O(1) )检查两个系列是否是彼此的排列。然而,在最坏的情况下,它将是O(n log n)/ O(1)

答案 5 :(得分:1)

解决方案需要O(n)时间并且空间为O(1)。 这省去了排序,空间O(1)的要求是一个提示,你可能应该对字符串进行哈希并比较它们。

如果您可以访问素数列表,请按照cheeken的解决方案进行操作。

注意:如果面试官说您无法访问素数列表。然后生成素数并存储它们。这是O(1)因为字母长度是常数。

另外,这是我的另类想法。为简单起见,我将Alphabet定义为= {a,b,c,d,e}。 字母的值定义为:

a, b, c, d, e
1, 2, 4, 8, 16

注意:如果面试官说这是不允许的,那么为Alphabet做一个查找表,这需要O(1)空间,因为Alphabet的大小是常量

定义一个可以在字符串中找到不同字母的函数。

// set bit value of char c in variable i and return result
distinct(char c, int i) : int

E.g. distinct('a', 0) returns 1
E.g. distinct('a', 1) returns 1
E.g. distinct('b', 1) returns 3

因此,如果你迭代字符串“aab”,那么distinct函数应该给出3作为结果

定义一个可以计算字符串中字母总和的函数。

// return sum of c and i
sum(char c, int i) : int

E.g. sum('a', 0) returns 1
E.g. sum('a', 1) returns 2
E.g. sum('b', 2) returns 4

因此,如果你迭代字符串“aab”,sum函数应该给出4作为结果

定义一个可以计算字符串中字母长度的函数。

// return length of string s
length(string s) : int

E.g. length("aab") returns 3

在两个字符串上运行方法并比较结果需要O(n)运行时间。存储哈希值在空间中占用O(1)。

 e.g. 
 distinct of "aab" => 3
 distinct of "aba" => 3
 sum of "aab => 4
 sum of "aba => 4
 length of "aab => 3
 length of "aba => 3

由于两个字符串的所有值都相等,因此它们必须是彼此的排列。

编辑:解决方案与评论中指出的给定字母值不一致。

答案 6 :(得分:0)

您可以将两个阵列中的一个转换为就地哈希表。这不完全是O(N),但在非病理情况下它会接近。

只需使用[number%N]作为所需的索引或从那里开始的链中。如果必须替换任何元素,则可以将其放置在违规元素开始的索引处。冲洗,洗涤,重复。

更新: This is a similar (N=M) hash table它确实使用了链接,但它可以降级为开放寻址。

答案 7 :(得分:0)

我使用的是一个误差率低的随机算法。

关键是使用universal hash function

def hash(array, hash_fn):
  cur = 0
  for item in array:
    cur ^= hash_item(item)
  return cur

def are_perm(a1, a2):
  hash_fn = pick_random_universal_hash_func()
  return hash_fn(a1, hash_fn) == hash_fn(a2, hash_fn) 

如果数组是排列,那么它总是正确的。如果它们不同,算法可能错误地说它们是相同的,但它会以非常低的概率这样做。此外,通过在同一输入上询问许多are_perm()问题,你可以通过在同一输入上询问许多are_perm()问题来获得指数减少的错误几率,然后它们肯定不是彼此的排列。

答案 8 :(得分:0)

我只是找到一个反例。所以,下面的假设是不正确的。


我无法证明这一点,但我认为这可能是真的。

由于数组的所有元素都是整数,假设每个数组都有2个元素, 我们有

a1 + a2 = s
a1 * a2 = m

b1 + b2 = s
b1 * b2 = m

then {a1, a2} == {b1, b2}

如果这是真的,那么数组就有n个元素。

所以我们比较每个数组的总和和乘积,如果它们相等,则一个是排列 另一个。