LeetCode 78. Subsets

Given an integer array nums of unique elements, return all possible subsets (the power set).

The solution set must not contain duplicate subsets. Return the solution in any order.

Both solutions below take O(n*2^n) time.

Using enumerate binary numbers:

class Solution:
    def subsets(self, nums: List[int]) -> List[List[int]]:
        """Create power set by counting in binary"""
        n = len(nums)
        hi = 1 << n

        subsets = []
        for i in range(hi):
            new_subset = []
            k = 0
            while i > 0:
                if i & 1:
                    new_subset.append(nums[k])

                i >>= 1
                k += 1

            subsets.append(new_subset)

        return subsets

Backtracking:

class Solution:
    def subsets(self, nums: List[int]) -> List[List[int]]:
        def backtrack(first = 0, curr = []):
            # if the combination is done
            if len(curr) == k:
                output.append(curr[:])
                return
            for i in range(first, n):
                # add nums[i] into the current combination
                curr.append(nums[i])
                # use next integers to complete the combination
                backtrack(i + 1, curr)
                # backtrack
                curr.pop()

        output = []
        n = len(nums)
        for k in range(n + 1):
            backtrack()
        return output

LeetCode 1155. Number of Dice Rolls With Target Sum

You have n dice and each die has k faces numbered from 1 to k.

Given three integers n, k, and target, return the number of possible ways (out of the kn total ways) to roll the dice so the sum of the face-up numbers equals target. Since the answer may be too large, return it modulo 10^9 + 7.

Constraints:

1 <= n, k <= 30
1 <= target <= 1000
from functools import cache

class Solution:
    def numRollsToTarget(self, d: int, f: int, target: int) -> int:

        @cache
        def dfs(t, d):
            if t == 0 and d == 0: return 1
            if d <= 0 or t <= 0: return 0
            return sum(dfs(t-i, d-1) for i in range(1, f+1))

        return dfs(target, d) % int(1e9 + 7)

LeetCode 236. Lowest Common Ancestor of a Binary Tree

Given a binary tree, find the lowest common ancestor (LCA) of two given nodes in the tree.

According to the definition of LCA on Wikipedia: “The lowest common ancestor is defined between two nodes p and q as the lowest node in T that has both p and q as descendants (where we allow a node to be a descendant of itself).”

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution:
    def lowestCommonAncestor(self,
    root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode':
        if root in (None, p, q):
          return root
        left, right = (self.lowestCommonAncestor(kid, p, q)
                       for kid in (root.left, root.right))
        return root if left and right else left or right

LeetCode 62. Unique Paths

There is a robot on an m x n grid. The robot is initially located at the top-left corner (i.e., grid[0][0]). The robot tries to move to the bottom-right corner (i.e., grid[m - 1][n - 1]). The robot can only move either down or right at any point in time.

Given the two integers m and n, return the number of possible unique paths that the robot can take to reach the bottom-right corner.

The test cases are generated so that the answer will be less than or equal to `2

  • 10^9`.
class Solution:
    def uniquePaths(self, m: int, n: int) -> int:
        @cache
        def dfs(i, j):
            if i >= m or j >= n:      return 0
            if i == m-1 and j == n-1: return 1
            return dfs(i+1, j) + dfs(i, j+1)
        return dfs(0, 0)
class Solution:
    def uniquePaths(self, m: int, n: int) -> int:
      """Alternates between two rows"""
        dp = [[1]*n for i in range(2)]
        for i in range(1,m):
            for j in range(1,n):
                dp[i&1][j] = dp[(i-1)&1][j] + dp[i&1][j-1]

        return dp[(m-1)&1][-1]