Practice #016: Leetcode
Leetcode: 279. Perfect Squares
Retrospective: The Top-down solution received time-limit and I had to code the Dynamic Programming.
This problem is a variation of Knapsack problem, but on this one the value is always 1 for each used item.
class Solution: def numSquares(self, n: int) -> int: inf = 10**5 ps = [] for i in range(1, n + 1): if i * i > n: break ps.append(i * i) dp = [inf] * (n + 1) dp[0] = 0 for i in range(1, n + 1): for s in ps: if s > i: continue dp[i] = min(dp[i], 1 + dp[i - s]) return dp[n] assert Solution().numSquares(12) == 3 assert Solution().numSquares(13) == 2
Leetcode: 1145. Binary Tree Coloring Game
For nodes in the tree, color it as blue if possible, find the path between it and each node in the path following the problem's rule. After it is done, count the number of blue nodes (colored and not accessible by any red node) and the number of red nodes. If there is no initial node which blue wins, return false otherwise true. Time complexity is \(O(n^2)\) and space \(O(n)\).
from functools import cache # Definition for a binary tree node. # class TreeNode: # def __init__(self, val=0, left=None, right=None): # self.val = val # self.left = left # self.right = right class Solution: def btreeGameWinningMove(self, root: Optional[TreeNode], n: int, x: int) -> bool: @cache def count(node): if node is None: return 0 return 1 + count(node.left) + count(node.right) def path(node, val): if node is None: return (False, []) if node.val == val: return (True, [node]) l = path(node.left, val) if l[0]: l[1].append(node) return l r = path(node.right, val) if r[0]: r[1].append(node) return r return (False, []) def print_nodes(r): print(list(map(lambda n: n.val, r))) ans = False _, r1 = path(root, x) for y in range(1, n + 1): if y == x: continue _, r2 = path(root, y) i = len(r1) - 1 j = len(r2) - 1 while i >= 0 and j >= 0 and r1[i] == r2[j]: i -= 1 j -= 1 p = r1[:i+2] + list(reversed(r2[:j+1])) if len(p) % 2 == 0: i = len(p) // 2 - 1 j = i + 1 else: i = (len(p) + 1) // 2 - 1 j = i + 1 if (p[j] in (p[i].left, p[i].right)) and n - count(p[j]) < count(p[j]): return True if (p[i] in (p[j].left, p[j].right)) and count(p[i]) < n - count(p[i]): return True return False
Leetcode: 1066. Campus Bikes II
This is a classic Dynamic Programming. We try to pair, one by one, all workers with all bikes while keeping track of the used bikes. Search-space is \(O(n \times 2^m)\) and time complexity is \(O(m)\) with a total time complexity of \(O(n \times m \times 2^m)\).
from functools import cache from typing import List class Solution: def assignBikes(self, workers: List[List[int]], bikes: List[List[int]]) -> int: n = len(workers) m = len(bikes) def dist(a, b): return abs(a[0] - b[0]) + abs(a[1] - b[1]) @cache def dfs(i, vis): if i == n: return 0 ans = None for j in range(m): if (vis & (1 << j)) != 0: continue cur = dist(workers[i], bikes[j]) + dfs(i + 1, vis | (1 << j)) if ans is None or ans > cur: ans = cur return ans return dfs(0, 0) assert Solution().assignBikes([[0, 0], [2, 1]], [[1, 2], [3, 3]]) == 6 assert Solution().assignBikes([[0, 0], [1, 1], [2, 0]], [[1, 0], [2, 2], [2, 1]]) == 4 assert ( Solution().assignBikes( [[0, 0], [1, 0], [2, 0], [3, 0], [4, 0]], [[0, 999], [1, 999], [2, 999], [3, 999], [4, 999]], ) == 4995 )