from typing import NamedTuple def check_balanced(root: BinaryTreeNode) -> bool: class Result(NamedTuple): is_balanced: bool height: int def helper(node: BinaryTreeNode, height: int) -> Result: if node is None: return Result(True, height) l: Result = helper(node.left, height + 1) r: Result = helper(node.right, height + 1) if not l.is_balanced or not r.is_balanced: return Result(False, max(l.height, r.height)) if abs(l.height - r.height) > 1: return Result(False, max(l.height, r.height)) return Result(True, max(l.height, r.height)) return helper(root, 0).is_balanced Solution(check_balanced, [ Test([parse_tree('1(2(2,),3(1,))')], True, None), Test([parse_tree('1(2(2,3),3)')], True, None), Test([parse_tree('1(2(2,3(1,2)),3)')], False, None), Test([parse_tree('1(2(1(2,),),3(1(2,),))')], False, None), ])
cur = head else: cur.next = SinglyNode(data) cur = cur.next num = num // base return head def sum_linked_list(a: SinglyNode, b: SinglyNode) -> SinglyNode: total = linked_list_to_num(a) + linked_list_to_num(b) return num_to_linked_list(total) Solution(sum_linked_list, [ Test([parse('1>2>3').head, parse('4>5>6').head], parse('5>7>9').head, None) ]) def add_lists(a: SinglyNode, b: SinglyNode, carry=0) -> SinglyNode: result = carry if a is None and b is None: if result != 0: return SinglyNode(carry) return None elif a is not None and b is not None: result += a.data + b.data elif a is not None:
def create_bst(sorted_list: List[int]) -> BinaryTreeNode: def helper(start: int, end: int) -> BinaryTreeNode: if start > end: return None mid = (start + end)//2 node = BinaryTreeNode(sorted_list[mid]) node.left = helper(start, mid-1) node.right = helper(mid+1, end) return node return helper(0, len(sorted_list) - 1) Solution( create_bst, [ Test( [ [1, 2, 3, 4, 5] ], parse_tree('3(1(,2),4(,5))'), None ) ] )
from algo_problems.utils.linked_list import SinglyNode, parse from algo_problems.utils.testing import Solution, Test def delete_middle(node: SinglyNode): while node.next is not None: node.data = node.next.data if node.next.next is None: node.next = None break node = node.next t1 = parse('1>2>3>4>5') Solution(delete_middle, [Test([t1.k_th(2)], parse('1>2>4>5'), t1)])
from algo_problems.utils.testing import Solution, Test def is_unique_chars(string: str) -> bool: if len(string) > 128: return False seen_table = [False] * 128 for l in string: index = ord(l) if seen_table[index]: return False else: seen_table[index] = True return True Solution(is_unique_chars, [Test(['ab'], True), Test(['aba'], False)])
count_all_spaces = 0 for c in char_list: if c == ' ': count_all_spaces += 1 # Space is normally 1 character while %20 is 3 # 2 additional characters per space count_spaces = count_all_spaces // 3 offset = count_spaces * 2 # Reverse for loop to take advantage of buffer at end # and not overwriting anything when moving for i in range((true_length - 1) - offset, 0, -1): c = char_list[i] if c != ' ': char_list[i + offset] = c else: char_list[i + offset] = '0' char_list[i + offset - 1] = '2' char_list[i + offset - 2] = '%' # For the buffer we have 'lost' offset -= 2 if offset == 0: return char_list # For testing return char_list Solution(urlify, [ Test([list('Mr John Smith '), 17], list('Mr%20John%20Smith')), ])
from algo_problems.utils.testing import Test, Solution def is_rotation(s1: str, s2: str) -> bool: if len(s1) != len(s2): return False xyxy = s1 + s1 return (s2 in xyxy) Solution(is_rotation, [ Test(['waterbottle', 'erbottlewat'], True), Test(['waterbottles', 'ewatserbottle'], False) ])
from algo_problems.utils.testing import Solution, Test # NOTE: Can only use one additional stack def sort_stack(s: list): temp_stack = [] while len(s) != 0: temp = s.pop() while len(temp_stack) != 0 and temp_stack[-1] > temp: s.append(temp_stack.pop()) temp_stack.append(temp) while len(temp_stack) != 0: s.append(temp_stack.pop()) s1 = [2, 3, 1, 5] Solution(sort_stack, [Test([s1], [5, 3, 2, 1], s1)])
from typing import List from algo_problems.utils.testing import Test, Solution def rotate(m: List[List[int]]) -> List[List[int]]: n = len(m) for layer in range(int(n / 2)): first = layer last = n - (1 + layer) for i in range(first, last): offset = i - first top = m[first][i] m[first][i] = m[last - offset][first] # Left -> Top m[last - offset][first] = m[last][last - offset] # Bottom -> Left m[last][last - offset] = m[i][last] # Right -> Bottom m[i][last] = top # Top -> Right return m Solution(rotate, [ Test([[[1, 2, 3], [4, 5, 6], [7, 8, 9]]], [ [7, 4, 1], [8, 5, 2], [9, 6, 3], ]) ])
return True test_table = [ Test( [parse('1>2>3>5>3>2>1').head], True, None ), Test( [parse('1>2>3>3>2>1').head], True, None ) ] Solution( is_palindrome, test_table ) class Result: def __init__(self, node: SinglyNode = None, match: bool = False): self.node = node self.match = match def is_palindrome_rec(head: SinglyNode) -> bool: mid = get_length(head) def helper(node: SinglyNode, length: int) -> Result: # node is None is the case when you are given an empty list if node is None or length <= 0: return Result(node, True)
return helper(v, w, {}) def has_path2(g: UndirectedGraph, v: int, w: int) -> bool: q = Queue() seen: Dict[i, bool] = {} q.enqueue(v) while not q.is_empty(): u = q.dequeue() if u in seen: pass else: if u == w: return True for vertex in g.adj(u): q.enqueue(vertex) return False g1 = build_simple_graph(7, [(1, 2), (2, 6), (2, 5), (4, 5), (3, 1), (3, 6)]) Solution(has_path, [Test([g1, 1, 3], False, None), Test([g1, 3, 5], True, None)]) Solution(has_path2, [Test([g1, 1, 3], False, None), Test([g1, 3, 5], True, None)])
return p1 p2 = p2.next p1 = p1.next def kth_last_rec(head: SinglyNode, k: int) -> Any: class IntWrapper: def __init__(self, val: int = 0): self.val = val def helper(helper_head: SinglyNode, k: int, w: IntWrapper) -> SinglyNode: if helper_head is None: return None node = helper(helper_head.next, k, w) w.val += 1 if w.val == k: return helper_head return node return helper(head, k, IntWrapper(val=0)) Solution(kth_last_rec, [ Test([parse('1>2>3>4').head, 2], SinglyNode(3)), Test([parse('1>2>3>4').head, 1], SinglyNode(4)), Test([parse('1').head, 1], SinglyNode(1)) ])
from algo_problems.utils.testing import Solution, Test def check_permutation(a: str, b: str) -> bool: freq_table = [0] * 128 if len(a) != len(b): return False for l in a: val = ord(l) freq_table[val] += 1 for l in b: val = ord(l) freq_table[val] -= 1 if freq_table[val] == -1: return False return True Solution(check_permutation, [ Test(['aba', 'ab'], False), Test(['same', 'mase'], True), Test(['diff', 'diph'], False) ])
Solution( zero_matrix, [ Test( [ [ [1, 2, 3], [1, 2, 0] ] ], [ [1, 2, 0], [0, 0, 0] ] ), Test( [ [ [0, 2, 3], [1, 2, 0] ] ], [ [0, 0, 0], [0, 0, 0] ] ) ] )
tail.next = None return head_to_linked_list(head) # t1 = parse('3>5>8>5>10>2>1') # Solution( # partition, # [ # Test( # [t1.head, 5], # parse('3>2>1>5>10>5>8'), # t1 # ) # ] # ) # t1 = parse('3>5>8>5>10>2>1') # Solution( # partition2, # [ # Test( # [t1.head, 5], # parse('1>2>3>10>5>8>5'), # t1 # ) # ] # ) t1 = parse('3>5>8>5>10>2>1') Solution(partition3, [Test([t1.head, 5], parse('1>2>3>5>8>5>10'), None)])
while True: if slow == fast: return True elif fast is None or fast.next is None: return False slow = slow.next fast = fast.next.next # Circular list x = SinglyNode(2) x.next = SinglyNode(1) x.next.next = SinglyNode(3) x.next.next.next = x Solution( is_circlular, [ Test( [x], True, None ), Test( [parse('1>2>3>1>2>4').head], False, None ) ] )
while j < len(s): if s[i] == s[j]: count += 1 j += 1 else: new_s += s[i] + str(count) i = j break if j >= len(s): if j > len(s): return s new_s += s[i] + str(count) break if len(new_s) >= len(s): return s return new_s Solution(compress_string, [ Test(['aaabb'], 'a3b2'), Test(['aaabbba'], 'a3b3a1'), Test(['a'], 'a'), Test([''], ''), Test(['aba'], 'aba'), Test(['aaaaa'], 'a5'), ])
node = node.next return head def remove_dups_no_buffer(head: SinglyNode) -> SinglyNode: current = head if head is None: return head while current is not None: runner = current while runner.next is not None: if runner.next.data == current.data: runner.next = runner.next.next else: runner = runner.next current = current.next return head Solution(remove_dups_no_buffer, [ Test([parse('1>1').head], parse('1').head), Test([parse('1>2>3>2').head], parse('1>2>3').head) ])