3 minute read

934. Shortest Bridge (medium)

class Solution:
    def shortestBridge(self, grid: List[List[int]]) -> int:
        n = len(grid)
        q, head = [], -1
        dis = []
        visited = [[False] * n for _ in range(n)]
        for i in range(n):
            for j in range(n):
                if grid[i][j] == 1:
                    q = [[i, j]]
                    visited[i][j] = True
                    dis.append(0)
                    break
            if len(q) > 0:
                break
        dirs = [[0, 1], [0, -1], [1, 0], [-1, 0]]
        while head < len(q) - 1:
            head += 1
            x, y = q[head][0], q[head][1]
            for d in dirs:
                xx, yy = x + d[0], y + d[1]
                if xx < 0 or xx >= n or yy < 0 or yy >= n:
                    continue
                if visited[xx][yy] or grid[xx][yy] == 0:
                    continue
                q.append([xx, yy])
                visited[xx][yy] = True
                dis.append(0)
        head = -1
        while head < len(q) - 1:
            head += 1
            x, y = q[head][0], q[head][1]
            for d in dirs:
                xx, yy = x + d[0], y + d[1]
                if xx < 0 or xx >= n or yy < 0 or yy >= n or visited[xx][yy]:
                    continue
                q.append([xx, yy])
                visited[xx][yy] = True
                dis.append(dis[head] + 1)
                if grid[xx][yy] == 1:
                    return dis[-1] - 1
        return 0

935. Knight Dialer (medium)

class Solution:
    def knightDialer(self, n: int) -> int:
        tree = [
            [4, 6], 
            [8, 6], 
            [7, 9], 
            [4, 8], 
            [3, 9, 0], 
            [], 
            [1, 7, 0], 
            [2, 6],
            [1, 3],
            [4, 2],
        ]

        dp = {}

        @functools.lru_cache(None)
        def dfs(cur, count):
            if count <= 1:
                return count
            res = 0
            for num in tree[cur]:
                res += dfs(num, count - 1)
            # dp[cur][count] = res
            return res

        res = 0
        for i in range(10):
            res += dfs(i, n)

        return res % (10**9 + 7)
            

Memoization Approach

class Solution:
    def knightDialer(self, n: int) -> int:
        MOD = 10 ** 9 + 7
        dp = [1] * 10
        for _ in range(n - 1):
            new_dp = [0] * 10
            new_dp[0] = (dp[4] + dp[6]) % MOD
            new_dp[7] = (dp[2] + dp[6]) % MOD
            new_dp[8] = (dp[1] + dp[3]) % MOD
            new_dp[4] = (dp[3] + dp[9] + dp[0]) % MOD
            new_dp[5] = 0
            new_dp[1] = (dp[6] + dp[8]) % MOD
            new_dp[2] = (dp[7] + dp[9]) % MOD
            new_dp[3] = new_dp[1]
            new_dp[6] = new_dp[4]
            new_dp[9] = new_dp[7]
            dp = new_dp
        return sum(dp) % MOD

936. Stamping The Sequence (hard)

Failed

class Solution:
    def movesToStamp(self, stamp: str, target: str) -> List[int]:
        n = len(stamp)
        m = len(target)
        visited = [0] * m
        res = []
        left, right = math.inf, -math.inf
        for i in range(m - n + 1):
            if stamp == target[i:i + n]:
                left = min(left, i)
                right = max(right, i + n)
                for j in range(i, i + n):
                    visited[j] = 1
                res.append(i)

        def extend():
            nonlocal left, right
            for j in range(max(0, left - n), left):
                # print(target[j:left])
                if target[j:left] in stamp:
                    left = j
                    res.append(j)
                    break
            for j in range(min(m, right + n + 1), right, -1):
                # print(target[right:j])
                if target[right:j] in stamp:
                    right = j
                    res.append(j - n)
                    break
                
        count = len(res)
        while left > 0 or right < m:
            # print(res, left, right)
            extend()
            count += 1
            if count > 10 * len(target):
                return []

        return res[::-1]

Greedy Approach

class Solution:
    def movesToStamp(self, stamp: str, target: str) -> List[int]:
        N,M = len(target),len(stamp)
        move = 0
        maxmove = 10*N
        ans = []
        def check(string):
            for i in range(M):
                if string[i] == stamp[i] or string[i] == '?':
                    continue
                else:
                    return False
            return True
        
        while move < maxmove:
            premove = move
            for i in range(N-M+1):
                if check(target[i:i+M]):
                    move += 1
                    ans.append(i)
                    target = target[:i] + "?"*M + target[i+M:]
                    if target == "?"*N : return ans[::-1]
            if premove == move:return []
        return []

939. Minimum Area Rectangle (medium)

class Solution:
    def minAreaRect(self, points: List[List[int]]) -> int:
        res = math.inf
        d = set()
        for point in points:
            d.add(tuple(point))
        
        def help(point):
            nonlocal res
            x, y = point
            for p in points:
                a, b = p
                if x == a or y == b: continue
                if (x, b) in d and (a, y) in d:
                    res = min(res, abs((x - a) * (y - b)))

        for point in points:
            help(point)

        return res if res != math.inf else 0