====== string.py ======
* 구버전 코드는 [[string_old]]로.
===== z_array =====
==== 코드 ====
# N z_array
# I {"version": "1.0"}
def z_array(s: str) -> list[int]:
"""Returns Z array of given string. (z[0]==len(s))"""
n = len(s)
l, r, z = 0, 0, [0]
for i in range(1, n):
z_i = min(r - i + 1, z[i - l]) if i <= r else 0
while i + z_i < n and s[z_i] == s[i + z_i]:
z_i += 1
if i + z_i - 1 > r:
l, r = i, i + z_i - 1
z.append(z_i)
z[0] = n
return z
==== 설명 ====
* z algorithm을 적용해서 z-array를 계산한다
==== 이 코드를 사용하는 문제 ====
---- struct table ----
schema: ps
cols: site, prob_id, %title%, prob_level
filter: teflib ~ *[string.z_array]*
csv: 0
----
===== Trie =====
==== 코드 ====
# N Trie
# I {"version": "2.0", "typing": ["Generator", "Generic", "Iterable", "TypeVar"]}
_CharLike = TypeVar('_CharLike')
_StrLike = Iterable[_CharLike]
_TrieNode = int
class Trie(Generic[_CharLike]):
def __init__(self, words: Iterable[_StrLike] = ()):
self.ROOT = 0
self.word_counts = [0]
self.child_counts = None
self.children = [{}]
for word in words:
self.add(word)
def add(self, word: _StrLike) -> _TrieNode:
"""Adds the given word to trie and returns a node for it."""
node = self.ROOT
for ch in word:
try:
node = self.children[node][ch]
except KeyError:
new_node = len(self.children)
self.children.append({})
self.word_counts.append(0)
self.children[node][ch] = new_node
node = new_node
self.word_counts[node] += 1
return node
def prefixes(self, word: _StrLike) -> Generator[_TrieNode, None, None]:
"""Yields all nodes for prefixes of the given word."""
node = self.ROOT
return ((node := self.children[node][ch]) for ch in word)
def nodes(self) -> Iterable[_TrieNode]:
return range(1, len(self.children))
def words(self) -> Iterable[_TrieNode]:
return (x for x in self.nodes() if self.word_counts[x] > 0)
def get_child_count(self, node: _TrieNode) -> int:
def count_rec(node):
if self.child_counts[node] is None:
self.child_counts[node] = sum(
count_rec(child) + self.word_counts[child]
for child in self.children[node].values())
return self.child_counts[node]
if not self.child_counts:
self.child_counts = [None] * len(self.children)
return count_rec(node)
==== 설명 ====
* [[ps:트라이]] 참고
==== 이 코드를 사용하는 문제 ====
===== palindrome_radiuses =====
==== 코드 ====
# N palindrome_radiuses
# I {"version": "1.01", "typing": ["Sequence", "TypeVar"], "const": ["T"]}
def palindrome_radiuses(text: Sequence[T]):
"""Implementation of Manacher's algorithm."""
end = center = -1
radiuses = []
for i in range(len(text)):
rad = min(end - i - 1, radiuses[center * 2 - i]) if i < end else 0
left = i - rad - 1
right = i + rad + 1
try:
while text[left] == text[right]:
rad += 1
left -= 1
right += 1
except IndexError:
pass
if right > end:
center, end = i, right
radiuses.append(rad)
return radiuses
==== 설명 ====
* Manacher's algorithm 을 구현한 것으로 [[ps:가장 긴 팰린드롬 부분문자열]]을 참고.
* 원본 문자열을 그대로 인자로 넘겨서 돌리면 홀수 길이 팰린드롬에 대한 정보밖에 얻지 못하므로, 대부분의 경우에는 문자열의 각 문자 사이에 특수문자를 추가하는 식으로 문자열을 변형하여서 인자로 넘긴다.
==== 이 코드를 사용하는 문제 ====
---- struct table ----
schema: ps
cols: site, prob_id, %title%, prob_level
filter: teflib ~ *[palindrome_radiuses]*
csv: 0
----