我试图找到一个解决方案,但无法解决这个问题。
我们得到两个未排序的整数数组A和B.我们必须检查数组B是否是A的排列。如何做到这一点。甚至对数字进行异或也不会起作用,因为可能有几个具有相同XOR值的反例不是彼此的排列。
解决方案需要O(n)时间并且空间为O(1)
欢迎任何帮助!! 感谢。
答案 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推算有助于此,原因有两个。
示例:
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)
如果我们不需要就地排序,那么以下方法可能有效:
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个元素。
所以我们比较每个数组的总和和乘积,如果它们相等,则一个是排列 另一个。