2023-11-01 04:12:36 +00:00
|
|
|
import collections.abc
|
2023-10-21 19:45:16 +00:00
|
|
|
import copy
|
2023-10-26 00:15:43 +00:00
|
|
|
import random
|
2023-10-19 15:23:24 +00:00
|
|
|
import typing
|
|
|
|
|
2023-10-21 12:23:14 +00:00
|
|
|
import stdlib
|
|
|
|
|
2023-10-19 15:23:24 +00:00
|
|
|
|
|
|
|
def yep(s: str) -> bool:
|
|
|
|
return s.strip().lower().startswith("y")
|
|
|
|
|
|
|
|
|
|
|
|
def guess_bisect_repl(lower: int, upper: int) -> int:
|
|
|
|
mid = lower + ((upper - lower) // 2)
|
|
|
|
|
|
|
|
if yep(input(f"is it {mid}? ")):
|
|
|
|
return mid
|
|
|
|
|
|
|
|
if yep(input(f"higher than {mid}? ")):
|
|
|
|
return guess_bisect_repl(mid, upper)
|
|
|
|
|
|
|
|
return guess_bisect_repl(lower, mid)
|
|
|
|
|
|
|
|
|
|
|
|
def find_sqrt_ish(n: int) -> int:
|
|
|
|
return int(find_bisect(0, n, gen_sqrt_check(n)))
|
|
|
|
|
|
|
|
|
|
|
|
def gen_sqrt_check(n: int) -> typing.Callable[[float], int]:
|
|
|
|
def check(mid: float) -> int:
|
|
|
|
mid_sq: float = mid * mid
|
|
|
|
|
|
|
|
if mid_sq == n:
|
|
|
|
return 0
|
|
|
|
|
|
|
|
if mid_sq < n:
|
|
|
|
return 1
|
|
|
|
|
|
|
|
return -1
|
|
|
|
|
|
|
|
return check
|
|
|
|
|
|
|
|
|
2023-10-20 14:38:20 +00:00
|
|
|
def find_bisect(
|
|
|
|
lower: float, upper: float, check: typing.Callable[[float], int]
|
|
|
|
) -> float:
|
2023-10-19 15:23:24 +00:00
|
|
|
mid: float = lower + ((upper - lower) / 2)
|
|
|
|
|
|
|
|
print(f"lower={lower} mid={mid} upper={upper}")
|
|
|
|
|
|
|
|
if mid == lower or mid == upper or check(mid) == 0:
|
|
|
|
return mid
|
|
|
|
|
|
|
|
if check(mid) == 1:
|
|
|
|
return find_bisect(mid, upper, check)
|
|
|
|
|
|
|
|
return find_bisect(lower, mid, check)
|
2023-10-20 11:57:25 +00:00
|
|
|
|
|
|
|
|
|
|
|
def cartesian_path(p0: tuple[int, int], p1: tuple[int, int]) -> list[tuple[int, int]]:
|
|
|
|
path: list[tuple[int, int]] = []
|
|
|
|
|
|
|
|
if p0 < p1:
|
|
|
|
for i in range(p0[1], p1[1]):
|
|
|
|
path.append((i, p0[0]))
|
|
|
|
|
|
|
|
for i in range(p0[0], p1[0]):
|
|
|
|
path.append((p1[1], i))
|
|
|
|
|
|
|
|
else:
|
|
|
|
for i in range(p0[1], p1[1] - 1, -1):
|
|
|
|
path.append((i, p0[0]))
|
|
|
|
|
|
|
|
for i in range(p0[0] - 1, p1[0], -1):
|
|
|
|
path.append((p1[1], i))
|
|
|
|
|
|
|
|
return path
|
|
|
|
|
|
|
|
|
|
|
|
def gen_matrix(width: int, height: int) -> list[list[int]]:
|
|
|
|
return [list(range(width)) for _ in range(height)]
|
2023-10-20 14:38:20 +00:00
|
|
|
|
|
|
|
|
2023-10-21 11:18:56 +00:00
|
|
|
class MinStack:
|
|
|
|
def __init__(self):
|
|
|
|
self._v: list[int] = []
|
2023-10-21 11:25:38 +00:00
|
|
|
self._min: list[int] = []
|
2023-10-21 11:18:56 +00:00
|
|
|
|
|
|
|
def push(self, val: int) -> None:
|
|
|
|
self._v.append(val)
|
2023-10-21 11:25:38 +00:00
|
|
|
self._min.append(min(val, self._min[-1] if self._min else val))
|
2023-10-21 11:18:56 +00:00
|
|
|
|
|
|
|
def pop(self) -> None:
|
2023-10-21 11:25:38 +00:00
|
|
|
self._v.pop(-1)
|
|
|
|
self._min.pop(-1)
|
2023-10-21 11:18:56 +00:00
|
|
|
|
|
|
|
def top(self) -> int:
|
|
|
|
return self._v[-1]
|
|
|
|
|
|
|
|
def getMin(self) -> int: # no qa
|
2023-10-21 11:25:38 +00:00
|
|
|
return self._min[-1]
|
2023-10-21 12:23:14 +00:00
|
|
|
|
|
|
|
|
2023-10-24 12:12:35 +00:00
|
|
|
def linked_list_to_list(head: stdlib.LinkedListNode | None) -> list[int]:
|
2023-10-21 12:23:14 +00:00
|
|
|
seen: set[int] = set()
|
|
|
|
ret: list[int] = []
|
|
|
|
|
|
|
|
while head is not None:
|
|
|
|
if hash(head) in seen:
|
|
|
|
return ret
|
|
|
|
|
|
|
|
seen.add(hash(head))
|
|
|
|
ret.append(head.val)
|
|
|
|
head = head.next
|
|
|
|
|
|
|
|
return ret
|
|
|
|
|
|
|
|
|
2023-10-24 12:12:35 +00:00
|
|
|
def sort_linked_list(head: stdlib.LinkedListNode | None) -> stdlib.LinkedListNode | None:
|
|
|
|
by_val: list[tuple[int, stdlib.LinkedListNode]] = []
|
|
|
|
ret: stdlib.LinkedListNode | None = None
|
2023-10-21 12:23:14 +00:00
|
|
|
|
|
|
|
while head is not None:
|
|
|
|
by_val.append((head.val, head))
|
|
|
|
head = head.next
|
|
|
|
|
|
|
|
cur = ret
|
|
|
|
|
2023-10-21 12:41:41 +00:00
|
|
|
for _, node in sorted(by_val, key=lambda v: v[0]):
|
2023-10-21 12:23:14 +00:00
|
|
|
if cur is None:
|
2023-10-21 12:41:41 +00:00
|
|
|
cur = ret = node
|
2023-10-21 12:23:14 +00:00
|
|
|
continue
|
|
|
|
|
2023-10-21 12:41:41 +00:00
|
|
|
cur.next = node
|
|
|
|
cur = cur.next
|
|
|
|
|
|
|
|
if cur is not None:
|
|
|
|
cur.next = None
|
2023-10-21 12:23:14 +00:00
|
|
|
|
|
|
|
return ret
|
2023-10-21 19:45:16 +00:00
|
|
|
|
|
|
|
|
|
|
|
def connect_binary_tree_right(
|
2023-10-24 12:12:35 +00:00
|
|
|
root: stdlib.ConnectableBinaryTreeNode | None,
|
|
|
|
) -> tuple[stdlib.ConnectableBinaryTreeNode | None, list[int | None]]:
|
2023-10-21 19:45:16 +00:00
|
|
|
if root is None:
|
|
|
|
return None, []
|
|
|
|
|
|
|
|
by_level = binary_tree_by_level(copy.deepcopy(root))
|
2023-10-24 12:12:35 +00:00
|
|
|
by_level = typing.cast(dict[int, list[stdlib.ConnectableBinaryTreeNode]], by_level)
|
2023-10-21 19:45:16 +00:00
|
|
|
serialized: list[int | None] = []
|
|
|
|
|
2023-10-21 20:19:13 +00:00
|
|
|
print("")
|
|
|
|
|
|
|
|
if 0 not in by_level or len(by_level[0]) == 0:
|
|
|
|
return None, []
|
|
|
|
|
|
|
|
connected_root = by_level[0][0]
|
|
|
|
|
|
|
|
for level, nodes in sorted(by_level.items(), key=lambda p: p[0]):
|
2023-10-21 19:45:16 +00:00
|
|
|
for i in range(len(nodes)):
|
|
|
|
serialized.append(nodes[i].val)
|
|
|
|
|
2023-10-21 20:19:13 +00:00
|
|
|
if len(nodes) > i + 1:
|
|
|
|
print(f"{'-' * level}> connecting {nodes[i].val} -> {nodes[i + 1].val}")
|
2023-10-21 19:45:16 +00:00
|
|
|
nodes[i].next = nodes[i + 1]
|
|
|
|
|
|
|
|
serialized.append(None)
|
|
|
|
|
2023-10-21 20:19:13 +00:00
|
|
|
return connected_root, serialized
|
2023-10-21 19:45:16 +00:00
|
|
|
|
|
|
|
|
2023-10-24 12:12:35 +00:00
|
|
|
def binary_tree_by_level(
|
|
|
|
root: stdlib.BinaryTreeNode,
|
|
|
|
) -> dict[int, list[stdlib.BinaryTreeNode]]:
|
|
|
|
combined: dict[int, list[stdlib.BinaryTreeNode]] = {}
|
2023-10-21 19:45:16 +00:00
|
|
|
|
|
|
|
for path in collect_binary_tree_levels(0, root):
|
|
|
|
level, node = path
|
|
|
|
combined.setdefault(level, [])
|
|
|
|
combined[level].insert(0, node)
|
|
|
|
|
|
|
|
return combined
|
|
|
|
|
|
|
|
|
|
|
|
def collect_binary_tree_levels(
|
2023-10-24 12:12:35 +00:00
|
|
|
level: int, node: stdlib.BinaryTreeNode | None
|
|
|
|
) -> typing.Iterator[tuple[int, stdlib.BinaryTreeNode]]:
|
2023-10-21 19:45:16 +00:00
|
|
|
if node is None:
|
|
|
|
return
|
|
|
|
|
|
|
|
yield (level, node)
|
|
|
|
yield from collect_binary_tree_levels(level + 1, node.right)
|
|
|
|
yield from collect_binary_tree_levels(level + 1, node.left)
|
2023-10-21 20:34:42 +00:00
|
|
|
|
|
|
|
|
2023-10-24 12:12:35 +00:00
|
|
|
def sum_binary_tree_path_ints(root: stdlib.BinaryTreeNode | None) -> int:
|
2023-10-21 20:34:42 +00:00
|
|
|
path_ints: list[int] = []
|
|
|
|
|
|
|
|
for path in collect_binary_tree_paths(root):
|
|
|
|
path_ints.append(int("".join([str(node.val) for node in path])))
|
|
|
|
|
|
|
|
return sum(path_ints)
|
|
|
|
|
|
|
|
|
2023-10-24 12:12:35 +00:00
|
|
|
def binary_tree_paths_as_lists(
|
|
|
|
paths: list[list[stdlib.BinaryTreeNode]],
|
|
|
|
) -> list[list[int]]:
|
|
|
|
paths_vals: list[list[int]] = []
|
|
|
|
|
|
|
|
for path in paths:
|
|
|
|
paths_vals.append([node.val for node in path])
|
|
|
|
|
|
|
|
return paths_vals
|
|
|
|
|
|
|
|
|
2023-10-21 20:34:42 +00:00
|
|
|
def collect_binary_tree_paths(
|
2023-10-24 12:12:35 +00:00
|
|
|
node: stdlib.BinaryTreeNode | None,
|
|
|
|
) -> typing.Iterator[list[stdlib.BinaryTreeNode]]:
|
2023-10-21 20:34:42 +00:00
|
|
|
if node is None:
|
|
|
|
return
|
|
|
|
|
|
|
|
if node.right is None and node.left is None:
|
|
|
|
yield [node]
|
|
|
|
return
|
|
|
|
|
|
|
|
if node.right is not None:
|
|
|
|
for path in collect_binary_tree_paths(node.right):
|
|
|
|
yield [node] + path
|
|
|
|
|
|
|
|
if node.left is not None:
|
|
|
|
for path in collect_binary_tree_paths(node.left):
|
|
|
|
yield [node] + path
|
2023-10-24 12:12:35 +00:00
|
|
|
|
|
|
|
|
|
|
|
def binary_tree_from_list(inlist: list[int | None]) -> stdlib.BinaryTreeNode | None:
|
|
|
|
if len(inlist) == 0:
|
|
|
|
return None
|
|
|
|
|
|
|
|
nodes: list[stdlib.BinaryTreeNode | None] = [
|
|
|
|
typing.cast(stdlib.BinaryTreeNode | None, stdlib.TreeNode.from_int(i))
|
|
|
|
for i in inlist
|
|
|
|
]
|
|
|
|
nodes_copy = nodes[::-1]
|
|
|
|
root = nodes_copy.pop()
|
|
|
|
|
|
|
|
for node in nodes:
|
|
|
|
if node is None:
|
|
|
|
continue
|
|
|
|
|
|
|
|
if len(nodes_copy) == 0:
|
|
|
|
break
|
|
|
|
|
|
|
|
node.left = nodes_copy.pop()
|
|
|
|
|
|
|
|
if len(nodes_copy) > 0:
|
|
|
|
node.right = nodes_copy.pop()
|
|
|
|
|
|
|
|
return root
|
2023-10-24 19:42:42 +00:00
|
|
|
|
|
|
|
|
|
|
|
def binary_tree_from_preorder_inorder(
|
|
|
|
preorder: list[int], inorder: list[int]
|
|
|
|
) -> stdlib.BinaryTreeNode | None:
|
|
|
|
preorder_reversed = preorder[::-1]
|
|
|
|
|
|
|
|
def subtree(left: list[int], right: list[int]) -> stdlib.BinaryTreeNode:
|
|
|
|
root: stdlib.BinaryTreeNode = typing.cast(
|
|
|
|
stdlib.BinaryTreeNode, stdlib.TreeNode(preorder_reversed.pop())
|
|
|
|
)
|
|
|
|
|
|
|
|
if len(left) > 1:
|
|
|
|
split_pos = left.index(preorder_reversed[-1])
|
|
|
|
root.left = subtree(left[:split_pos], left[split_pos + 1 :])
|
|
|
|
elif len(left) == 1:
|
|
|
|
preorder_reversed.remove(left[0])
|
|
|
|
root.left = typing.cast(stdlib.BinaryTreeNode, stdlib.TreeNode(left[0]))
|
|
|
|
|
|
|
|
if len(right) > 1:
|
|
|
|
split_pos = right.index(preorder_reversed[-1])
|
|
|
|
root.right = subtree(right[:split_pos], right[split_pos + 1 :])
|
|
|
|
elif len(right) == 1:
|
|
|
|
preorder_reversed.remove(right[0])
|
|
|
|
root.right = typing.cast(stdlib.BinaryTreeNode, stdlib.TreeNode(right[0]))
|
|
|
|
|
|
|
|
return root
|
|
|
|
|
|
|
|
split_pos = inorder.index(preorder[0])
|
|
|
|
|
|
|
|
return subtree(inorder[:split_pos], inorder[split_pos + 1 :])
|
2023-10-24 23:46:01 +00:00
|
|
|
|
|
|
|
|
|
|
|
class JumpSpace(typing.NamedTuple):
|
|
|
|
pos: int
|
|
|
|
val: int
|
|
|
|
moves: list["JumpSpace"]
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
def from_board(
|
|
|
|
cls, pos: int = 0, board: typing.Iterable[int] = ()
|
|
|
|
) -> typing.Optional["JumpSpace"]:
|
|
|
|
board = list(board)
|
|
|
|
|
|
|
|
if len(board) == 0:
|
|
|
|
return None
|
|
|
|
|
|
|
|
space = cls(pos, board[pos], [])
|
|
|
|
space.collect(board)
|
|
|
|
return space
|
|
|
|
|
|
|
|
def collect(self, board: list[int]) -> None:
|
|
|
|
del self.moves[:]
|
|
|
|
|
|
|
|
if self.pos > len(board) or len(board) == 0:
|
|
|
|
return
|
|
|
|
|
|
|
|
for n in range(self.pos + 1, self.pos + self.val + 1):
|
|
|
|
if n >= len(board):
|
|
|
|
break
|
|
|
|
|
|
|
|
self.moves.append(typing.cast(JumpSpace, JumpSpace.from_board(n, board)))
|
|
|
|
|
|
|
|
def jump_paths(self) -> list[list[int]]:
|
|
|
|
ret: list[list[int]] = [[self.pos]]
|
|
|
|
|
|
|
|
for next_space in self.moves:
|
|
|
|
for path in next_space.jump_paths():
|
|
|
|
ret.append([self.pos] + path)
|
|
|
|
|
|
|
|
return ret
|
|
|
|
|
|
|
|
|
|
|
|
def collect_complete_jump_paths_from_board(board: list[int]) -> list[list[int]]:
|
|
|
|
return [
|
|
|
|
p
|
|
|
|
for p in collect_jump_paths_from_board(board)
|
|
|
|
if len(p) > 0 and p[-1] >= len(board) - 1
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
|
|
def collect_jump_paths_from_board(board: list[int]) -> list[list[int]]:
|
|
|
|
space = JumpSpace.from_board(0, board)
|
|
|
|
if space is None:
|
|
|
|
return []
|
|
|
|
|
|
|
|
return space.jump_paths()
|
2023-10-25 20:51:35 +00:00
|
|
|
|
|
|
|
|
|
|
|
# NOTE: the expensive way goes like this
|
|
|
|
# complete_paths = collect_complete_jump_paths_from_board(board)
|
|
|
|
|
|
|
|
# if len(complete_paths) == 0:
|
|
|
|
# return -1
|
|
|
|
|
|
|
|
# return min([len(p) - 1 for p in complete_paths])
|
|
|
|
|
|
|
|
|
|
|
|
def count_min_jumps_from_board(board: list[int]) -> int:
|
|
|
|
return len(collect_min_jumps_from_board(board))
|
|
|
|
|
|
|
|
|
|
|
|
def collect_min_jumps_from_board(board: list[int]) -> list[int]:
|
|
|
|
if len(board) < 3:
|
|
|
|
return list(range(1, len(board)))
|
|
|
|
|
|
|
|
jumps: list[int] = []
|
|
|
|
range_begin: int = 0
|
|
|
|
val = board[range_begin]
|
|
|
|
range_end: int = range_begin + val + 1
|
|
|
|
|
|
|
|
while range_end < len(board):
|
|
|
|
potential_jumps = board[range_begin:range_end]
|
|
|
|
|
|
|
|
scored_jumps = [
|
|
|
|
(val + range_begin + i, val, range_begin + i)
|
|
|
|
for i, val in enumerate(potential_jumps)
|
|
|
|
]
|
|
|
|
_, val, space = max(scored_jumps)
|
|
|
|
|
|
|
|
jumps.append(space)
|
|
|
|
|
|
|
|
range_begin = space
|
|
|
|
range_end = range_begin + val + 1
|
|
|
|
|
|
|
|
return jumps + [len(board) - 1]
|
2023-10-25 23:18:05 +00:00
|
|
|
|
|
|
|
|
|
|
|
def h_index(citations: list[int]) -> int:
|
|
|
|
last_qualified = None
|
|
|
|
|
2023-10-25 23:19:00 +00:00
|
|
|
for i, citation_count in enumerate(list(sorted(citations, reverse=True))):
|
|
|
|
if citation_count >= i + 1:
|
2023-10-25 23:18:05 +00:00
|
|
|
last_qualified = i + 1
|
|
|
|
else:
|
|
|
|
break
|
|
|
|
|
|
|
|
return last_qualified or 0
|
2023-10-26 00:15:43 +00:00
|
|
|
|
|
|
|
|
2023-10-26 07:58:50 +00:00
|
|
|
class SlowRandomizedSet:
|
2023-10-26 00:15:43 +00:00
|
|
|
def __init__(self):
|
|
|
|
self._i: set[int] = set()
|
|
|
|
|
|
|
|
def insert(self, val: int) -> bool:
|
|
|
|
ok = val not in self._i
|
|
|
|
self._i.add(val)
|
|
|
|
return ok
|
|
|
|
|
|
|
|
def remove(self, val: int) -> bool:
|
|
|
|
if val in self._i:
|
|
|
|
self._i.remove(val)
|
|
|
|
return True
|
|
|
|
return False
|
|
|
|
|
|
|
|
def getRandom(self) -> int:
|
2023-10-26 07:58:50 +00:00
|
|
|
return random.choice(list(self._i))
|
|
|
|
|
|
|
|
|
|
|
|
class RandomizedSet:
|
|
|
|
def __init__(self):
|
|
|
|
self._l: list[int] = []
|
|
|
|
self._m: dict[int, int] = {}
|
|
|
|
|
|
|
|
def insert(self, val: int) -> bool:
|
|
|
|
if val in self._m:
|
|
|
|
return False
|
|
|
|
|
|
|
|
self._m[val] = len(self._l)
|
|
|
|
self._l.append(val)
|
|
|
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
def remove(self, val: int) -> bool:
|
|
|
|
if val not in self._m:
|
|
|
|
return False
|
|
|
|
|
|
|
|
val_loc = self._m[val]
|
|
|
|
last_val = self._l[-1]
|
|
|
|
self._l[val_loc] = last_val
|
|
|
|
self._m[last_val] = val_loc
|
|
|
|
|
|
|
|
self._l.pop()
|
|
|
|
self._m.pop(val)
|
|
|
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
def getRandom(self) -> int:
|
|
|
|
return random.choice(self._l)
|
2023-10-26 23:59:11 +00:00
|
|
|
|
|
|
|
|
|
|
|
class TrieNode(typing.NamedTuple):
|
|
|
|
value: str
|
|
|
|
kids: dict[str, "TrieNode"]
|
|
|
|
|
2023-10-27 12:19:03 +00:00
|
|
|
@property
|
|
|
|
def is_leaf(self) -> bool:
|
|
|
|
return "__self__" in self.kids
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
def leaf(cls) -> "TrieNode":
|
|
|
|
return cls("__self__", {})
|
|
|
|
|
2023-10-26 23:59:11 +00:00
|
|
|
|
|
|
|
class Trie:
|
|
|
|
def __init__(self):
|
2023-10-27 12:19:03 +00:00
|
|
|
self._root_node = TrieNode("", {})
|
2023-10-26 23:59:11 +00:00
|
|
|
|
|
|
|
def insert(self, word: str) -> None:
|
2023-10-27 12:19:03 +00:00
|
|
|
if len(word) == 0:
|
|
|
|
return
|
2023-10-26 23:59:11 +00:00
|
|
|
|
2023-10-27 12:19:03 +00:00
|
|
|
current_node = self._root_node
|
2023-10-26 23:59:11 +00:00
|
|
|
|
2023-10-27 12:19:03 +00:00
|
|
|
for prefix in [word[: i + 1] for i in range(len(word))]:
|
|
|
|
current_node.kids.setdefault(prefix, TrieNode(prefix, {}))
|
|
|
|
current_node = current_node.kids[prefix]
|
2023-10-26 23:59:11 +00:00
|
|
|
|
2023-10-27 12:19:03 +00:00
|
|
|
leaf = TrieNode.leaf()
|
|
|
|
current_node.kids[leaf.value] = leaf
|
2023-10-27 00:44:05 +00:00
|
|
|
|
2023-10-26 23:59:11 +00:00
|
|
|
def search(self, word: str) -> bool:
|
|
|
|
return self._has(word, prefix_ok=False)
|
|
|
|
|
|
|
|
def startsWith(self, prefix: str) -> bool:
|
|
|
|
return self._has(prefix, prefix_ok=True)
|
|
|
|
|
|
|
|
def _has(self, word: str, prefix_ok: bool) -> bool:
|
2023-10-27 12:19:03 +00:00
|
|
|
if len(word) == 0:
|
|
|
|
return True
|
2023-10-26 23:59:11 +00:00
|
|
|
|
2023-10-27 12:19:03 +00:00
|
|
|
reverse_path = [word[: i + 1] for i in range(len(word))][::-1]
|
|
|
|
current_node = self._root_node
|
2023-10-26 23:59:11 +00:00
|
|
|
|
2023-10-27 12:19:03 +00:00
|
|
|
while reverse_path and current_node is not None:
|
|
|
|
current_node = current_node.kids.get(reverse_path.pop())
|
2023-10-26 23:59:11 +00:00
|
|
|
|
2023-10-27 12:19:03 +00:00
|
|
|
return (
|
|
|
|
current_node is not None
|
|
|
|
and (current_node.is_leaf or prefix_ok)
|
|
|
|
and current_node.value == word
|
|
|
|
)
|
2023-10-27 20:12:17 +00:00
|
|
|
|
|
|
|
|
|
|
|
def count_factorial_trailing_zeroes(number: int) -> int:
|
|
|
|
divisor: int = 5
|
|
|
|
zeroes_count: int = 0
|
|
|
|
|
|
|
|
while divisor <= number:
|
|
|
|
zeroes_count += number // divisor
|
|
|
|
divisor *= 5
|
|
|
|
|
|
|
|
return zeroes_count
|
2023-10-27 21:33:22 +00:00
|
|
|
|
|
|
|
|
|
|
|
def copy_random_list(
|
|
|
|
head: stdlib.ListNodeRandom | None,
|
|
|
|
) -> stdlib.ListNodeRandom | None:
|
|
|
|
if head is None:
|
|
|
|
return None
|
|
|
|
|
|
|
|
ordered = []
|
|
|
|
cur = head
|
|
|
|
while cur is not None:
|
|
|
|
ordered.append(cur)
|
|
|
|
cur = cur.next
|
|
|
|
|
|
|
|
ordered_copy = [stdlib.ListNodeRandom(entry.val) for entry in ordered]
|
|
|
|
|
|
|
|
hash_idx = {hash(n): i for i, n in enumerate(ordered)}
|
|
|
|
|
|
|
|
for i, entry in enumerate(ordered):
|
|
|
|
if i + 1 < len(ordered_copy):
|
|
|
|
ordered_copy[i].next = ordered_copy[i + 1]
|
|
|
|
|
|
|
|
if entry.random is not None:
|
|
|
|
ordered_copy[i].random = ordered_copy[hash_idx[hash(entry.random)]]
|
|
|
|
|
|
|
|
return ordered_copy[0]
|
2023-10-28 12:21:39 +00:00
|
|
|
|
|
|
|
|
|
|
|
def sum_max_sub_array(nums: list[int]) -> int:
|
2023-10-31 04:58:52 +00:00
|
|
|
mmax = last = prev = nums[0]
|
|
|
|
|
|
|
|
for i in range(1, len(nums)):
|
|
|
|
prev = nums[i] + last
|
|
|
|
last = max(nums[i], prev)
|
|
|
|
mmax = max(mmax, last)
|
|
|
|
|
|
|
|
return mmax
|
|
|
|
|
|
|
|
|
2023-10-31 12:00:18 +00:00
|
|
|
def sum_max_sub_array_i(nums: list[int]) -> tuple[int, int]:
|
|
|
|
mmax_i: int = 0
|
|
|
|
mmax = last = prev = nums[0]
|
|
|
|
|
|
|
|
for i in range(1, len(nums)):
|
|
|
|
prev = nums[i] + last
|
|
|
|
last = max(nums[i], prev)
|
|
|
|
mmax_i = i if last > mmax else mmax_i
|
|
|
|
mmax = max(mmax, last)
|
|
|
|
|
|
|
|
return mmax_i, mmax
|
|
|
|
|
|
|
|
|
2023-10-31 04:58:52 +00:00
|
|
|
def sum_max_sub_array_accum(nums: list[int]) -> int:
|
|
|
|
accum: list[int] = [nums[0]]
|
|
|
|
|
|
|
|
for i in range(1, len(nums)):
|
|
|
|
prev: int = nums[i] + accum[-1]
|
|
|
|
accum.append(max(nums[i], prev))
|
|
|
|
|
|
|
|
return max(accum)
|
|
|
|
|
|
|
|
|
|
|
|
def accum_sub_array_maxes(nums: list[int]) -> list[int]:
|
|
|
|
accum: list[int] = [nums[0]]
|
|
|
|
|
|
|
|
for i in range(1, len(nums)):
|
|
|
|
prev: int = nums[i] + accum[-1]
|
|
|
|
accum.append(max(nums[i], prev))
|
|
|
|
|
|
|
|
return accum
|
2023-11-01 04:12:36 +00:00
|
|
|
|
|
|
|
|
|
|
|
def neighborly_node_from_list(inlist: list[list[int]]):
|
|
|
|
# Alias "Node" type for leetcode compat
|
|
|
|
Node = stdlib.NeighborlyNodeNicely
|
|
|
|
|
|
|
|
if len(inlist) == 0:
|
|
|
|
return None
|
|
|
|
|
|
|
|
outlist = [Node(i + 1, []) for i in range(len(inlist))]
|
|
|
|
|
|
|
|
for i in range(len(inlist)):
|
|
|
|
outlist[i].neighbors[:] = []
|
|
|
|
|
|
|
|
for neighbor_val in inlist[i]:
|
|
|
|
outlist[i].neighbors.append(outlist[neighbor_val - 1])
|
|
|
|
|
|
|
|
return outlist[0]
|
|
|
|
|
|
|
|
|
|
|
|
def neighborly_node_to_list(node) -> list[list[int]]:
|
|
|
|
serialized: dict[int, list[int]] = {}
|
|
|
|
|
|
|
|
for cur in traverse_neighborly_node(node, serialized):
|
|
|
|
if cur is None:
|
|
|
|
break
|
|
|
|
|
|
|
|
serialized[cur.val] = [n.val for n in cur.neighbors]
|
|
|
|
|
|
|
|
return [v for _, v in sorted(serialized.items())]
|
|
|
|
|
|
|
|
|
|
|
|
def traverse_neighborly_node(
|
|
|
|
node: stdlib.NeighborlyNodeNicely, memo: collections.abc.Container[int]
|
|
|
|
) -> typing.Iterator[stdlib.NeighborlyNodeNicely | None]:
|
|
|
|
yield node
|
|
|
|
|
|
|
|
if node is None:
|
|
|
|
return
|
|
|
|
|
|
|
|
for neighbor in node.neighbors:
|
|
|
|
if neighbor.val in memo:
|
|
|
|
continue
|
|
|
|
|
|
|
|
yield from traverse_neighborly_node(neighbor, memo)
|