Did weeks 10-12

This commit is contained in:
Aaro Koivukangas
2026-03-26 17:03:42 +02:00
parent fc081ca68e
commit ac39ef540a
16 changed files with 695 additions and 0 deletions
+39
View File
@@ -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
+24
View File
@@ -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)
+23
View File
@@ -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
+31
View File
@@ -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]) != []
+52
View File
@@ -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)
+25
View File
@@ -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
+46
View File
@@ -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]
+21
View File
@@ -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
+38
View File
@@ -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)
+24
View File
@@ -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()
+12
View File
@@ -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]
+65
View File
@@ -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
+114
View File
@@ -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
+64
View File
@@ -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)
+67
View File
@@ -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) # []
+50
View File
@@ -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