文字列に慣れるためにいろいろな方法で解きます。
- 1: find, スライスで文字列比較
- 2: suffix検出をrfind
- 3: suffix検出をfindの開始位置指定
- 4: suffix検出をひっくり返してprefix判定にする
- 5: Z algorithm
- 6: ローリングハッシュ
- 7: 編集距離(レーベンシュタイン距離)
1: find, スライスで文字列比較
Pythonのfind()
は検出された最初の位置を返すので0か判定すればよいです。
Pythonのstr()[-k:]
は最後のk文字を取り出します。
答えの表示はboolでif分岐が妥当ですがじっと眺めると0b11
をxorすればよいです。
n, m = map(int, input().split())
s, t = input(), input()
ans = 3
if t.find(s) == 0: ans ^= 0b10
if t[-n:] == s: ans ^= 0b01
print(ans)
2: suffix検出をrfind
Pythonにはrfind
があり検出された最後の位置を返す関数があります。
if t.find(s) == 0: ans ^= 0b10
if t.rfind(s) == m-n: ans ^= 0b01
3: suffix検出をfindの開始位置指定
Pythonのfindはfind(sub[, start[, end]])
のstart
で開始位置を指定できます。
if t.find(s) == 0: ans ^= 0b10
if t.find(s, m-n) != -1: ans ^= 0b01
4: suffix検出をひっくり返してprefix判定にする
sがtのsuffixであるとは、sとtをひっくり返した状態でsがtのprefixであるか?と同値です。
Pythonではstr[::-1]
で文字列をひっくり返せます。
if t.find(s) == 0: ans ^= 0b10
s = s[::-1]
t = t[::-1]
if t.find(s) == 0: ans ^= 0b01
5: Z algorithm
Z algorithmは与えられた文字列におけるすべての位置$i$からの最長共通接頭辞長を$O(N)$で求められます。Z algorithmの典型としては文字列abc
とababc
があるとき、出現しない文字列_
などを用いてabc_ababc
をつくりこれを入力とします。
z = zAlgorithm(s + "_" + t)
# t開始からの最長共通接頭辞長がn以上ならprefix
if z.res[n+1] >= n: ans ^= 0b10
# 最後からn文字前の最長共通接頭辞長がn以上ならsuffix
if z.res[n+1+m-n] >= n: ans ^= 0b01
6: ローリングハッシュ
ローリングハッシュはO(N)
の事前計算をしておくことである区間の文字列のハッシュをO(1)
で求めることが出来ます。
rhs = rollingHash61(s)
rht = rollingHash61(t)
# それぞれ、[0,n)のhashが一緒ならprefix
if rhs.hash(0, n) == rht.hash(0, n): ans ^= 0b10
# sの[0,n)とtの[m-n, m)のhashが一緒ならsuffix
if rhs.hash(0, n) == rht.hash(m-n, m): ans ^= 0b01
7: 編集距離(レーベンシュタイン距離)
二つの文字列を字の挿入/削除/置換で一方を他方に変形するための最小手順回数です。
prefixはdistance(s, t) == m-n
でいいように思えますが、abc, aabc
のとき距離1になってしまうので"_"などの使われない文字をダミーで入れてやります。
if levenshtein_distance(s + "_"*(m-n), t) == m-n: ans ^= 0b10
if levenshtein_distance("_"*(m-n) + s, t) == m - n: ans ^= 0b01