From ac39ef540a2a52a23e9e0b1aaeb34367e7ac90c1 Mon Sep 17 00:00:00 2001 From: Aaro Koivukangas Date: Thu, 26 Mar 2026 17:03:42 +0200 Subject: [PATCH] Did weeks 10-12 --- viikko10/allsteps.py | 39 +++++++++++++ viikko10/coinsum.py | 24 ++++++++ viikko10/countlis.py | 23 ++++++++ viikko10/findlis.py | 31 ++++++++++ viikko10/formula.py | 52 +++++++++++++++++ viikko10/machine.py | 25 ++++++++ viikko11/fliplist.py | 46 +++++++++++++++ viikko11/fliptwo.py | 21 +++++++ viikko11/smallest_tenth.py | 38 +++++++++++++ viikko11/stack.py | 24 ++++++++ viikko11/tasklist.py | 12 ++++ viikko12/minmax.py | 65 +++++++++++++++++++++ viikko12/prevnext.py | 114 +++++++++++++++++++++++++++++++++++++ viikko12/treeheight.py | 64 +++++++++++++++++++++ viikko12/treeremove.py | 67 ++++++++++++++++++++++ viikko12/treesize.py | 50 ++++++++++++++++ 16 files changed, 695 insertions(+) create mode 100644 viikko10/allsteps.py create mode 100644 viikko10/coinsum.py create mode 100644 viikko10/countlis.py create mode 100644 viikko10/findlis.py create mode 100644 viikko10/formula.py create mode 100644 viikko10/machine.py create mode 100644 viikko11/fliplist.py create mode 100644 viikko11/fliptwo.py create mode 100644 viikko11/smallest_tenth.py create mode 100644 viikko11/stack.py create mode 100644 viikko11/tasklist.py create mode 100644 viikko12/minmax.py create mode 100644 viikko12/prevnext.py create mode 100644 viikko12/treeheight.py create mode 100644 viikko12/treeremove.py create mode 100644 viikko12/treesize.py diff --git a/viikko10/allsteps.py b/viikko10/allsteps.py new file mode 100644 index 0000000..025bf1c --- /dev/null +++ b/viikko10/allsteps.py @@ -0,0 +1,39 @@ +import math + + +def min_steps(x): + result = {} + result[1] = 0 + + for i in range(1, x + 1): + if result.get(i, -1) >= 0: + result[i + 3] = min(result.get(i + 3, math.inf), result[i] + 1) + result[i * 2] = min(result.get(i * 2, math.inf), result[i] + 1) + # print(f"i: {i}, curr: {result[i]}, +3 => {result[i+3]}, *2 => {result[i*2]}", x) + + print(result.get(x, -1)) + return result.get(x, -1) + + +def count_steps(x): + result = {} + result[1] = 1 + + for i in range(1, x + 1): + result[i + 3] = result.get(i + 3, 0) + result.get(i, 0) + result[i * 2] = result.get(i * 2, 0) + result.get(i, 0) + + print("Result:", result.get(x, 0), x) + return result.get(x, 0) + + +if __name__ == "__main__": + assert count_steps(1) == 1 + assert count_steps(2) == 1 + assert count_steps(3) == 0 + assert count_steps(4) == 2 + assert count_steps(5) == 1 + assert count_steps(17) == 5 + assert count_steps(42) == 0 + assert count_steps(100) == 242 + assert count_steps(1000) == 2948311 diff --git a/viikko10/coinsum.py b/viikko10/coinsum.py new file mode 100644 index 0000000..bd8d9f7 --- /dev/null +++ b/viikko10/coinsum.py @@ -0,0 +1,24 @@ +def can_create(coins, target): + result = {} + for x in range(target + 1): + result[x] = True if x in coins else False + + for i in range(1, target + 1): + for c in coins: + if i - c >= 0 and not result.get(i + c): + result[i + c] = True if result[i] or c == i else False + # print(f"Calc: {i:2} +{c:2} = {i+c:2} => {result[i+c]}, because previous {i-c} = {result[i-c]}") + + print("RESULT:", result[target]) + return result[target] + + +if __name__ == "__main__": + assert can_create([1], 1) + assert can_create([1, 2, 5], 13) + assert not can_create([2, 4, 6], 13) + assert can_create([1], 42) + assert can_create([2, 4, 6], 42) + assert not can_create([3], 1337) + assert can_create([3, 4], 1337) + assert can_create([3, 7, 9], 16) diff --git a/viikko10/countlis.py b/viikko10/countlis.py new file mode 100644 index 0000000..e716de0 --- /dev/null +++ b/viikko10/countlis.py @@ -0,0 +1,23 @@ +def count_sequences(numbers): + result = {} + len_result = {} + + max_len = 0 + for i in range(len(numbers)): + result[i] = 1 + for j in range(i): + if numbers[j] < numbers[i]: + result[i] = max(result[i], result[j] + 1) + max_len = max(max_len, result[i]) + len_result[result[i]] = len_result.get(result[i], 0) + 1 + + return len_result[max_len] + +if __name__ == "__main__": + print(count_sequences([1, 2, 3])) # 1 + print(count_sequences([3, 2, 1])) # 3 + print(count_sequences([1, 1, 1, 1, 1])) # 5 + + print(count_sequences([1, 8, 2, 7, 3, 6])) # 1 + print(count_sequences([1, 1, 2, 2, 3, 3])) # 8 + print(count_sequences([4, 1, 5, 6, 3, 4, 3, 8])) # 3 diff --git a/viikko10/findlis.py b/viikko10/findlis.py new file mode 100644 index 0000000..a7eaad3 --- /dev/null +++ b/viikko10/findlis.py @@ -0,0 +1,31 @@ +def find_sequence(numbers): + result = {} + for i in range(len(numbers)): + num = numbers[i] + result[num] = result.get(num, [num]) + + for key in result.keys(): + if key < num: + result[num] = result[key] + [num] if len(result[num]) <= len(result[key]) + 1 else result[num] + + longest = sorted(list(result.values()), key=len, reverse=True) + # print(longest) + # print() + return longest[0] + + + +if __name__ == "__main__": + assert find_sequence([1, 2, 3]) == [1, 2, 3] + assert find_sequence([3, 2, 1]) == [3] + assert find_sequence([1, 1, 1, 1, 1]) == [1] + assert find_sequence([1, 8, 2, 7, 3, 6]) == [1, 2, 3, 6] + + assert find_sequence([1, 1, 2, 2, 3, 3]) == [1, 2, 3] + assert find_sequence([4, 1, 5, 6, 3, 4, 3, 8]) == [1, 5, 6, 8] + assert find_sequence([9, 2, 9, 1]) == [2, 9] + assert find_sequence([8, 6, 1, 1, 9, 4, 7]) == [1, 4, 7] + assert find_sequence([10, 34, 43, 17, 33, 83, 73, 35, 92, 68, 33, 14, 13, 80]) == [10, 17, 33, 35, 68 ,80] + assert find_sequence([96, 80, 54, 81, 39, 42, 17, 13, 4, 10, 50, 26, 13, 95, 12, 8, 75, 38, 27, 68, 64, 36, 25, 89, 96]) != [] + assert find_sequence([65, 4, 62, 22, 47, 99, 83, 11, 23, 22, 61, 49, 9, 60, 32, 53, 59, 81, 36, 68, 66, 69, 47, 23, 29, 95, 85, 31, 83, 82, 44, 31, 19, 22, 97, 91, 48, 69, 49]) != [] + assert find_sequence([79, 26, 75, 65, 34, 29, 33, 73, 13, 10, 29, 43, 78, 8, 25, 9, 78, 28, 70, 58, 86, 87, 52, 7, 1, 81, 62, 44, 49, 15, 6, 14, 94, 37, 90, 61, 28, 39, 10, 72, 80, 95, 91, 65, 99, 60, 54, 68, 84, 76, 70, 54, 65, 54, 8, 37, 57, 87, 85, 32, 10, 44, 47, 5, 91, 17, 88]) != [] diff --git a/viikko10/formula.py b/viikko10/formula.py new file mode 100644 index 0000000..f7adb98 --- /dev/null +++ b/viikko10/formula.py @@ -0,0 +1,52 @@ +from fractions import Fraction +import decimal +import math +from math import factorial + + +def calc_binomial(a: int, b: int) -> int: + a_fact = factorial(a) + b_fact = factorial(b) + a_b_fact = factorial(a - b) + denominator = b_fact * a_b_fact + + # This has to be // for some reason... + result = a_fact // denominator + assert result == math.comb(a, b) + + return result + + +def count_sequences(n: int): + if n % 2 != 0: + return 0 + + n_div = n // 2 + assert n_div.is_integer() + + binomial = calc_binomial(n, n_div) + assert binomial.is_integer() + + # oh man this took time... + result_div = Fraction(1, (n_div + 1)) + result = round(result_div * binomial) + + return int(result) + + +if __name__ == "__main__": + assert count_sequences(1) == 0 + assert count_sequences(2) == 1 + assert count_sequences(3) == 0 + assert count_sequences(4) == 2 + assert count_sequences(5) == 0 + assert count_sequences(6) == 5 + + assert count_sequences(42) == 24466267020 + assert count_sequences(62) == 14544636039226909 + assert count_sequences(64) == 55534064877048198 + assert ( + count_sequences(1000) + == 539497486917039060909410566119711128734834348196703167679426896420410037336371644508208550747509720888947317534973145917768881736628103627844100238921194561723883202123256952806711505149177419849031086149939116975191706558395784192643914160118616272189452807591091542120727401415762287153293056320 + ) + assert count_sequences(5000) diff --git a/viikko10/machine.py b/viikko10/machine.py new file mode 100644 index 0000000..1a4a550 --- /dev/null +++ b/viikko10/machine.py @@ -0,0 +1,25 @@ +import math +def min_steps(x): + result = {} + result[1] = 0 + + for i in range(1, x + 1): + if result.get(i, -1) >= 0: + result[i + 3] = min(result.get(i+3, math.inf), result[i] + 1) + result[i * 2] = min(result.get(i*2, math.inf), result[i] + 1) + # print(f"i: {i}, curr: {result[i]}, +3 => {result[i+3]}, *2 => {result[i*2]}", x) + + print(result.get(x, -1)) + return result.get(x, -1) + + +if __name__ == "__main__": + assert min_steps(1) == 0 + assert min_steps(2) == 1 + assert min_steps(3) == -1 + assert min_steps(4) == 1 + assert min_steps(5) == 2 + assert min_steps(17) == 4 + assert min_steps(42) == -1 + assert min_steps(100) == 7 + assert min_steps(1000) == 13 diff --git a/viikko11/fliplist.py b/viikko11/fliplist.py new file mode 100644 index 0000000..517e1fd --- /dev/null +++ b/viikko11/fliplist.py @@ -0,0 +1,46 @@ +import collections + + +class FlipList: + def __init__(self): + self.l = collections.deque() + self.reverse = False + + def __repr__(self): + if self.reverse: + return str(list(reversed([x for x in self.l]))) + else: + return str([x for x in self.l]) + + def add_first(self, x): + if self.reverse: + self.l.append(x) + else: + self.l.appendleft(x) + + def add_last(self, x): + if self.reverse: + self.l.appendleft(x) + else: + self.l.append(x) + + def flip(self): + self.reverse = not self.reverse + + +if __name__ == "__main__": + numbers = FlipList() + + numbers.add_last(1) + numbers.add_last(2) + numbers.add_last(3) + print(numbers) # [1, 2, 3] + + numbers.add_first(4) + print(numbers) # [4, 1, 2, 3] + + numbers.flip() + print(numbers) # [3, 2, 1, 4] + + numbers.add_last(5) + print(numbers) # [3, 2, 1, 4, 5] diff --git a/viikko11/fliptwo.py b/viikko11/fliptwo.py new file mode 100644 index 0000000..34ce63d --- /dev/null +++ b/viikko11/fliptwo.py @@ -0,0 +1,21 @@ +import collections + + +def find_first(size, steps): + ls = collections.deque([x for x in range(1, size+1)]) + + for i in range(steps): + second = ls.popleft() + first = ls.popleft() + + ls.append(first) + ls.append(second) + + return ls[0] + +if __name__ == "__main__": + print(find_first(4, 3)) # 4 + print(find_first(12, 5)) # 11 + print(find_first(2, 1000)) # 1 + print(find_first(99, 555)) # 11 + print(find_first(12345, 10**6)) # 12295 diff --git a/viikko11/smallest_tenth.py b/viikko11/smallest_tenth.py new file mode 100644 index 0000000..3ce384d --- /dev/null +++ b/viikko11/smallest_tenth.py @@ -0,0 +1,38 @@ +import time +import random +import heapq + + +def smallest_tenth(n): + ls = random.choices(range(1, 10**9), k=n) + + start = time.time() + ls_sorted = sorted(ls) + result1 = sum(ls_sorted[: n // 10]) + end_sorted = time.time() + print("Did sorting") + + ls_heap = [] + for item in ls: + heapq.heappush(ls_heap, item) + result2 = sum([heapq.heappop(ls_heap) for _ in range(n // 10)]) + end_heap_iter = time.time() + print("Did heap_iter") + + heapq.heapify(ls) + result3 = sum([heapq.heappop(ls) for _ in range(n // 10)]) + end_heapify = time.time() + print("Did heapify") + + print(result1) + print(result2) + print(result3) + + print( + f"Total: {end_heapify - start:.2f}, sorted: {end_sorted - start:.2f}, heap_iter: {end_heap_iter - end_sorted:.2f}, heapify: {end_heapify - end_heap_iter:.2f}" + ) + assert result1 == result2 and result2 == result3 + + +if __name__ == "__main__": + smallest_tenth(10**7) diff --git a/viikko11/stack.py b/viikko11/stack.py new file mode 100644 index 0000000..873c6fe --- /dev/null +++ b/viikko11/stack.py @@ -0,0 +1,24 @@ +import collections +import time + +def stack(n): + start = time.time() + stack = collections.deque() + for x in range(n): + stack.append(x) + + add_end = time.time() + for x in range(n): + stack.popleft() + + end = time.time() + + return f"Total: {end - start:.2f} seconds, to add: {add_end - start:.2f}, to delete: {end - add_end:.2f}" + + + +def main(): + print(stack(10**5)) + +if __name__ == "__main__": + main() diff --git a/viikko11/tasklist.py b/viikko11/tasklist.py new file mode 100644 index 0000000..5311020 --- /dev/null +++ b/viikko11/tasklist.py @@ -0,0 +1,12 @@ +import heapq + + +class Tasks: + def __init__(self): + self.t = [] + + def add_task(self, name, priority): + heapq.heappush(self.t, (-priority, name)) + + def fetch_task(self): + return heapq.heappop(self.t)[1] diff --git a/viikko12/minmax.py b/viikko12/minmax.py new file mode 100644 index 0000000..493baef --- /dev/null +++ b/viikko12/minmax.py @@ -0,0 +1,65 @@ +class Node: + def __init__(self, value): + self.value = value + self.left = None + self.right = None + +class TreeSet: + def __init__(self): + self.root = None + + def add(self, value): + if not self.root: + self.root = Node(value) + return + + node = self.root + while True: + if node.value == value: + return + if node.value > value: + if not node.left: + node.left = Node(value) + return + node = node.left + else: + if not node.right: + node.right = Node(value) + return + node = node.right + + def min(self): + node = self.root + while True: + if node is None: + return None + if not node.left: + return node.value + node = node.left + + def max(self): + node = self.root + while True: + if node is None: + return None + if not node.right: + return node.value + node = node.right + +if __name__ == "__main__": + numbers = TreeSet() + + print(numbers.min()) # None + print(numbers.max()) # None + + numbers.add(3) + print(numbers.min()) # 3 + print(numbers.max()) # 3 + + numbers.add(4) + print(numbers.min()) # 3 + print(numbers.max()) # 4 + + numbers.add(1) + print(numbers.min()) # 1 + print(numbers.max()) # 4 diff --git a/viikko12/prevnext.py b/viikko12/prevnext.py new file mode 100644 index 0000000..4a521d3 --- /dev/null +++ b/viikko12/prevnext.py @@ -0,0 +1,114 @@ +import math +class Node: + def __init__(self, value): + self.value = value + self.left = None + self.right = None + + def __repr__(self): + return f"({self.value}, l: {self.left}, r: {self.right})" + + +class TreeSet: + def __init__(self): + self.root = None + + def add(self, value): + if not self.root: + self.root = Node(value) + return + + node = self.root + while True: + if node.value == value: + return + if node.value > value: + if not node.left: + node.left = Node(value) + return + node = node.left + else: + if not node.right: + node.right = Node(value) + return + node = node.right + + def prev(self, value): + node = self.root + + if node is None: + return None + + highest_lowest = 0 + while node: + print(value, node, highest_lowest) + if node.value < value: + highest_lowest = max(node.value, highest_lowest) + node = node.right + + elif value <= node.value: + node = node.left + + else: + break + + print("prev:", highest_lowest) + print() + if highest_lowest == 0: + return None + return highest_lowest + + def next(self, value): + node = self.root + + if node is None: + return None + + lowest_highest = math.inf + while node: + print(value, node, lowest_highest) + if value < node.value: + lowest_highest = min(node.value, lowest_highest) + node = node.left + + elif node.value <= value: + node = node.right + + else: + break + + print("next:", lowest_highest) + print() + if lowest_highest == math.inf: + return None + return lowest_highest + + +if __name__ == "__main__": + numbers = TreeSet() + + numbers.add(3) + numbers.add(2) + numbers.add(5) + numbers.add(7) + + assert numbers.prev(5) == 3 + assert numbers.prev(4) == 3 + assert numbers.prev(3) == 2 + assert numbers.prev(2) == None + + assert numbers.next(4) == 5 + assert numbers.next(5) == 7 + assert numbers.next(6) == 7 + assert numbers.next(7) == None + + numbers = TreeSet() + numbers.add(1) + assert numbers.prev(2) == 1 + assert numbers.next(2) == None + numbers.add(2) + assert numbers.prev(2) == 1 + assert numbers.next(2) == None + numbers.add(2) + assert numbers.prev(3) == 2 + assert numbers.next(1) == 2 diff --git a/viikko12/treeheight.py b/viikko12/treeheight.py new file mode 100644 index 0000000..da62eba --- /dev/null +++ b/viikko12/treeheight.py @@ -0,0 +1,64 @@ +import random +import time + + +class Node: + def __init__(self, value): + self.value = value + self.left = None + self.right = None + + +class TreeSet: + def __init__(self): + self.root = None + self.max_depth = -1 + + def add(self, value): + max_depth = 0 + + if not self.root: + self.root = Node(value) + self.max_depth += 1 + return + + node = self.root + while True: + if node.value == value: + break + max_depth += 1 + if node.value > value: + if not node.left: + node.left = Node(value) + break + node = node.left + else: + if not node.right: + node.right = Node(value) + break + node = node.right + + self.max_depth = max(self.max_depth, max_depth) + + def height(self): + return self.max_depth + + +if __name__ == "__main__": + start = time.time() + numbers_smallest = TreeSet() + for i in range(1000): + numbers_smallest.add(i) + result_smallest = numbers_smallest.height() + end_smallest = time.time() + + numbers_biggest = TreeSet() + for i in sorted([i for i in range(1000)], key=lambda x: random.random()): + numbers_biggest.add(i) + result_biggest = numbers_biggest.height() + end_biggest = time.time() + + print( + f"Total: {end_biggest - start:.2f}, smallest: {end_smallest - start:.2f}, biggest: {end_biggest - end_smallest:.2f}" + ) + print("Height smallest:", result_smallest, "Height biggest", result_biggest) diff --git a/viikko12/treeremove.py b/viikko12/treeremove.py new file mode 100644 index 0000000..a60c466 --- /dev/null +++ b/viikko12/treeremove.py @@ -0,0 +1,67 @@ +class Node: + def __init__(self, value): + self.value = value + self.left = None + self.right = None + + +class TreeSet: + def __init__(self): + self.root = None + + def add(self, value): + if not self.root: + self.root = Node(value) + return + + node = self.root + while True: + if node.value == value: + return + if node.value > value: + if not node.left: + node.left = Node(value) + return + node = node.left + else: + if not node.right: + node.right = Node(value) + return + node = node.right + + def remove(self, value): + pass + + def __repr__(self): + items = [] + self.traverse(self.root, items) + return str(items) + + def traverse(self, node, items): + if not node: + return + self.traverse(node.left, items) + items.append(node.value) + self.traverse(node.right, items) + + +if __name__ == "__main__": + numbers = TreeSet() + + numbers.add(3) + numbers.add(2) + numbers.add(5) + numbers.add(7) + print(numbers) # [2, 3, 5, 7] + + numbers.remove(3) + print(numbers) # [2, 5, 7] + + numbers.remove(7) + print(numbers) # [2, 5] + + numbers.remove(2) + print(numbers) # [5] + + numbers.remove(5) + print(numbers) # [] diff --git a/viikko12/treesize.py b/viikko12/treesize.py new file mode 100644 index 0000000..a2366d8 --- /dev/null +++ b/viikko12/treesize.py @@ -0,0 +1,50 @@ +class Node: + def __init__(self, value): + self.value = value + self.left = None + self.right = None + + +class TreeSet: + def __init__(self): + self.root = None + self.size = 0 + + def add(self, value): + if not self.root: + self.root = Node(value) + self.size += 1 + return + + node = self.root + while True: + if node.value == value: + return + if node.value > value: + if not node.left: + self.size += 1 + node.left = Node(value) + return + node = node.left + else: + if not node.right: + self.size += 1 + node.right = Node(value) + return + node = node.right + + def __len__(self): + return self.size + + +if __name__ == "__main__": + numbers = TreeSet() + print(len(numbers)) # 0 + numbers.add(1) + print(len(numbers)) # 1 + numbers.add(2) + print(len(numbers)) # 2 + numbers.add(3) + print(len(numbers)) # 3 + numbers.add(2) + print(len(numbers)) # 3