给定两个字符串,如何使用O(1)空间检查它们是否彼此置换?不允许以任何方式修改字符串。
注意:与字符串长度和字母大小有关的O(1)空间。
O(log n)
长度为n的字符串,长度既不取决于长度也不取决于字母大小。当可以临时修改字符串时,我认为存在一种解决方案,可以增加字母,字母大小是线性的,而对数模型中的字符串长度是恒定的。
给定两个字符串,如何使用O(1)空间检查它们是否彼此置换?不允许以任何方式修改字符串。
注意:与字符串长度和字母大小有关的O(1)空间。
O(log n)
长度为n的字符串,长度既不取决于长度也不取决于字母大小。当可以临时修改字符串时,我认为存在一种解决方案,可以增加字母,字母大小是线性的,而对数模型中的字符串长度是恒定的。
Answers:
天真的方法是建立两个字符串的直方图并检查它们是否相同。由于不允许我们存储这样的数据结构(其大小将与字母的大小成线性关系),可以一次计算出该数据结构,因此我们需要在另一个之后计算每个可能符号的出现次数:
function count(letter, string)
var count := 0
foreach element in string
if letter = element
count++
return count
function samePermutation(stringA, stringB)
foreach s in alphabet
if count(s, stringA) != count(s, stringB)
return false
return true
当然,这确实假定count和iterator索引是恒定大小的整数,而不是取决于字符串的长度。
O(n * min(n, |Σ|))
。嗯,现在我考虑一下,这听起来很像您回答中的“允许重复”解决方案,不是吗?
count
不是O(1)
(即可能会溢出)
用表示数组,并假设它们的长度为n。
首先假设每个数组中的值都是不同的。这是使用空间的算法:
计算两个数组的最小值,并检查它们是否相同。
计算两个数组的第二个最小值,并检查它们是否相同。
等等。
计算数组的最小值显然会占用空间。鉴于ķ个最小的元素,我们可以找到(ķ + 1 ), ST最小通过寻找最低值都比较大元素ķ个最小的元素(在这里我们使用的事实,所有的元素都是不同的)。
当允许重复元素时,我们将算法修改如下:
等等。
定义一些函数f(c),它将某些字符c映射到唯一的质数(a = 2,b = 3,c = 5,等等)。
set checksum = 1
set count = 0 <-- this is probably not even necessary, but it's another level of check
for character c in string 1
checksum = checksum * f(c)
count = count + 1
for character c in string 2
checksum = checksum / f(c)
count = count = 1
permutation = count == 0 and checksum == 1
您可以做到的是O(nlogn)
。对两个字符串进行排序,然后按索引对它们进行比较。如果它们在任何地方都不同,则它们并不是彼此置换。
对于O(n)
解决方案,可以使用哈希。此哈希函数将起作用,并且
e
对于任何字母将为其ascii值。如果字符串的两个哈希不同,则它们不是彼此置换。
链接中的哈希函数:
一个潜在的候选人可能就是这个。固定一个奇数R。对于每个要散列的元素e,计算因子(R + 2 * e)。然后计算所有这些因素的乘积。最后将乘积除以2得到哈希值。
(R + 2e)中的因数2保证所有因数均为奇数,因此避免了乘积将变为0。最后除以2是因为乘积将始终为奇数,因此除法仅除去了一个恒定位。
例如,我选择R =1779033703。这是一个任意选择,做一些实验应该表明给定的R是好是坏。假设您的值为[1、10、3、18]。乘积(使用32位整数计算)为
(R + 2)*(R + 20)*(R + 6)*(R + 36)= 3376724311因此哈希将为
3376724311/2 = 1688362155。
通过更改R的值使用双哈希(甚至更多用于过度杀伤)将成功地将其识别为排列的可能性很高。
假设您有两个名为s和t的字符串。
您可以使用试探法确保它们不相等。
之后,您可以轻松地运行算法以证明字符串相等。
当然,如果不允许使用额外的空间,则无法快速排序。因此,选择哪种算法都没有关系-当只有O(1)空间并且启发式方法无法证明它们不相等时,每种算法将需要O(n ^ 2)时间运行。
在整个例程的C风格代码中:
for (int i = 0; i < n; i++) {
int k = -1;
next: for (int j = 0; j <= i; j++)
if (A[j] == A[i]) {
while (++k < n)
if (B[k] == A[i])
continue next;
return false; // note at this point j == i
}
}
return true;
或使用非常冗长的伪代码(使用基于1的索引)
// our loop invariant is that B contains a permutation of the letters
// in A[1]..A[i-1]
for i=1..n
if !checkLetters(A, B, i)
return false
return true
其中,函数checkLetters(A,B,i)检查A [1] .. A [i]中是否有M个A [i]副本,然后B中至少有M个A [i]副本:
checkLetters(A,B,i)
k = 0 // scan index into B
for j=1..i
if A[j] = A[i]
k = findNextValue(B, k+1, A[i])
if k > n
return false
return true
函数findNextValue在B中搜索从索引开始的值,并返回找到它的索引(如果找不到,则返回n + 1)。
遍历string1
和string2
,对每个字符检查在string1
和中可以找到它的频率string2
。如果一个字符比另一个字符更经常出现在一个字符串中,那不是排列。如果所有字符的频率相等,则字符串是彼此排列的。
这是一段使这个精确的python
s1="abcaba"
s2="aadbba"
def check_if_permutations(string1, string2):
for string in [string1, string2]:
# string references string1
# string2, it is not a copy
for char in string:
count1=0
for char1 in string1:
if char==char1:
count1+=1
count2=0
for char2 in string2:
if char==char2:
count2+=1
if count1!=count2:
print('unbalanced character',char)
return()
print ("permutations")
return()
check_if_permutations(s1,s2)
string
string1
string2
char
char1
char2
count1
count2
string
[string1, string2]
当然,您甚至不需要count变量,但可以使用指针。
s1="abcaba"
s2="aadbba"
def check_if_permutations(string1, string2):
for string in [string1, string2]:
# string references one of string1
# or string2, it is not a copy
for char in string:
# p1 and p2 should be views as pointers
p1=0
p2=0
while (p1<len(string1)) and (p2<len(string2)):
# p1>=len(string1): p1 points to beyond end of string
while (p1<len(string1)) and (string1[p1]!=char) :
p1+=1
while(p2<len(string2)) and (string2[p2]!=char):
p2+=1
if (p1<len(string1)) != (p2<len(string2)):
print('unbalanced character',char)
return()
p1+=1
p2+=1
print ("permutations")
return()
check_if_permutations(s1,s2)