2つの文字列が与えられた場合、O(1)スペースを使用して、それらが互いの順列であるかどうかをどのように確認できますか 文字列を変更することは一切許可されていません。
注:文字列の長さとアルファベットのサイズの両方に関連するO(1)スペース。
O(log n)
するのは、長さもアルファベットサイズも一定ではない長さnの文字列です。文字列を一時的に変更できる場合、アルファベットサイズは線形ですが、対数モデルでは文字列の長さは一定である、アルファベットが増加したソリューションがあると思います。
2つの文字列が与えられた場合、O(1)スペースを使用して、それらが互いの順列であるかどうかをどのように確認できますか 文字列を変更することは一切許可されていません。
注:文字列の長さとアルファベットのサイズの両方に関連するO(1)スペース。
O(log n)
するのは、長さもアルファベットサイズも一定ではない長さnの文字列です。文字列を一時的に変更できる場合、アルファベットサイズは線形ですが、対数モデルでは文字列の長さは一定である、アルファベットが増加したソリューションがあると思います。
回答:
素朴なアプローチは、両方の文字列のヒストグラムを作成し、それらが同じかどうかを確認することです。1つのパスで計算できるようなデータ構造(サイズはアルファベットのサイズに線形になる)を保存することは許可されていないため、考えられる各シンボルの発生を次々にカウントする必要があります。
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
もちろん、これはカウントとイテレータインデックスが文字列の長さに依存するのではなく、一定サイズの整数であることを前提としています。
O(n * min(n, |Σ|))
ます。ええと、今考えてみると、それはあなたの答えから「繰り返すことを許された」解決策のように聞こえますよね?
count
ないO(1)
(つまり、オーバーフローする可能性があります)
配列を、長さがnであると仮定します。
まず、各配列の値が異なると仮定します。空間を使用するアルゴリズムは次のとおりです。
両方の配列の最小値を計算し、それらが同一であることを確認します。
両方の配列の2番目の最小値を計算し、それらが同一であることを確認します。
等々。
配列の最小値を計算するには、明らかにスペースが使用されます。与えられたkの最小番目の要素、我々は見つけることができます(K + 1 )より大きく、最小値求めることでST最小の要素のk番目の最小の要素を(ここでは、我々はすべての要素が明瞭であるという事実を使用します)。
要素の繰り返しが許可されている場合、アルゴリズムを次のように変更します。
両方の配列の最小値を計算し、それぞれが出現する回数をカウントし、m A 、1 = m B 、1およびカウントが同一であることを確認します。
2つの配列内のm A 、1、m B 、1より大きい最小値計算し(それぞれ)、それぞれの出現回数をカウントします。ことを確認し、M A 、2 = M B 、2、及び数が同一です。
等々。
文字cを一意の素数にマップする関数f(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)
。2つの文字列を並べ替え、それらをインデックスごとに比較します。どこでも異なる場合、それらは互いの順列ではありません。
以下のためにO(n)
解決策、ハッシュを使用することができます。このハッシュ関数は機能し
e
、どの文字に対してもASCII値になります。文字列の2つのハッシュが異なる場合、それらは互いの順列ではありません。
リンク内のハッシュ関数:
1つの潜在的な候補はこれかもしれません。奇数の整数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の値を変更してダブルハッシュを使用する(またはさらに過剰に使用する)と、Rが非常に高い確率で順列として正常に識別されます。
sとtという2つの文字列があるとします。
ヒューリスティックを使用して、それらが等しくないことを確認できます。
この後、文字列が等しいことを証明するアルゴリズムを簡単に実行できます。
もちろん、追加のスペースを使用することを許可されていない場合は、それほど速く並べ替えることはできません。したがって、どのアルゴリズムを選択しても問題ありません-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]にA [i]のMコピーがある場合、Bに少なくともA [i]のMコピーがあることをチェックします。
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
。文字は、他の文字列よりも1つの文字列に含まれていることが多いため、順列ではありません。すべての文字の頻度が等しい場合、文字列は互いの順列です。
これを正確にするための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]
もちろん、カウント変数も必要ありませんが、ポインターを使用できます。
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)