Skip to content

Commit 5dcafc9

Browse files
committed
hashing
1 parent 19a6361 commit 5dcafc9

File tree

1 file changed

+86
-0
lines changed

1 file changed

+86
-0
lines changed
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
# https://leetcode.com/problems/longest-palindrome-after-substring-concatenation-ii/
2+
# Very cool problem, many possible approaches (here I use hashing)
3+
# - Store all substring hashes of `t` (reversed) in a set
4+
# - We take a palindromic substring in `s` and try to add stuff to the left
5+
# - We can check if the stuff we add is valid by looking for the corresponding
6+
# strings in the `t` hashes
7+
#
8+
# Note: make sure 'a' doesn't become 0 when hashing or else we get collisions
9+
10+
MN = 2001
11+
p = 29
12+
mod = 1152921504606846989
13+
14+
power = [0] * MN
15+
power[0] = 1
16+
for i in range(1, MN):
17+
power[i] = (power[i - 1] * p) % mod
18+
19+
20+
def longestPalindrome(s: str, t: str) -> int:
21+
def solve(s, t):
22+
n, m = len(s), len(t)
23+
24+
# substrings of reversed `t`
25+
arr = [ord(i) - ord("a") + 1 for i in t][::-1]
26+
psa = [0] * (m + 1)
27+
for i in range(1, m + 1):
28+
psa[i] = (arr[i - 1] * power[MN - i] + psa[i - 1]) % mod
29+
subs = set()
30+
for l in range(m):
31+
for r in range(l, m):
32+
subs.add((psa[r + 1] - psa[l]) * power[l] % mod)
33+
34+
# hashes of `s`
35+
arr = [ord(i) - ord("a") + 1 for i in s]
36+
psa = [0] * (n + 1)
37+
for i in range(1, n + 1):
38+
psa[i] = (arr[i - 1] * power[MN - i] + psa[i - 1]) % mod
39+
40+
def query(l, r): # query hash of [l,r]
41+
# shift up to match `mn`
42+
hs = (psa[r + 1] - psa[l]) * power[l] % mod
43+
return hs
44+
45+
best = 0
46+
for cent in range(n):
47+
# odd case
48+
l = cent
49+
r = cent
50+
cur = 0
51+
while l >= 0 and r < n and s[l] == s[r]:
52+
cur = max(cur, r - l + 1)
53+
l -= 1
54+
r += 1
55+
for i in range(l + 1): # try extending left
56+
hs = query(i, l)
57+
if hs in subs: # found match in `t`
58+
cur += 2 * (l - i + 1)
59+
break
60+
best = max(best, cur)
61+
62+
# even case
63+
l = cent
64+
r = cent + 1
65+
cur = 0
66+
while l >= 0 and r < n and s[l] == s[r]:
67+
cur = max(cur, r - l + 1)
68+
l -= 1
69+
r += 1
70+
for i in range(l + 1): # try extending left
71+
hs = query(i, l)
72+
if hs in subs: # found match in `t`
73+
cur += 2 * (l - i + 1)
74+
break
75+
best = max(best, cur)
76+
return best
77+
78+
return max(solve(s, t), solve(t[::-1], s[::-1]))
79+
80+
81+
print(longestPalindrome("gaj", "gtld")) # 3
82+
print(longestPalindrome("n", "no")) # 2
83+
print(longestPalindrome("a", "a")) # 2
84+
print(longestPalindrome("abc", "def")) # 1
85+
print(longestPalindrome("b", "aaaa")) # 4
86+
print(longestPalindrome("abcde", "ecdba")) # 5

0 commit comments

Comments
 (0)