DFS, or Depth First Search, is a traversal algorithm used to explore graphs and trees. It starts from the root and explores each branch as far as possible before backtracking. This algorithm can be used to perform tree traversal in pre-order, in-order, and post-order. Often, the Stack data structure is used for DFS traversal.
BFS stands for Breadth-First Search, which is also known as level order traversal. As the name suggests, after traversing all the nodes in the current level, it will move on to the next level. Usually, the Queue data structure is used for the BFS traversal.
You can get a clear view of how DFS and BFS traverse a tree through the graph below:
Below is a list of practice problems from Leetcode about DFS and BFS. Happy coding!😄
• DFS
https://leetcode.com/problems/sum-root-to-leaf-numbers/
class Solution: def sumNumbers(self, root: Optional[TreeNode]) -> int: def dfs(node, num): if node is None: return 0 num = num * 10 + node.val if node.left == None and node.right == None: return num return dfs(node.left, num) + dfs(node.right, num) return dfs(root, 0)
https://leetcode.com/problems/path-sum-ii/
class Solution: def pathSum(self, root: Optional[TreeNode], targetSum: int) -> List[List[int]]: ans = [] def dfs(node, curSum, cur): if node == None: return cur.append(node.val) curSum += node.val if node.left == None and node.right == None and curSum == targetSum: ans.append(cur.copy()) dfs(node.left, curSum, cur) dfs(node.right, curSum, cur) cur.pop() dfs(root, 0, []) return ans
https://leetcode.com/problems/path-sum-iii/
class Solution: def pathSum(self, root: Optional[TreeNode], targetSum: int) -> int: self.ans = 0 lookup = {} def dfs(node, curSum): if node == None: return curSum += node.val if curSum == targetSum: self.ans += 1 if curSum - targetSum in lookup: self.ans += lookup[curSum - targetSum] lookup[curSum] = lookup.get(curSum, 0) + 1 dfs(node.left, curSum) dfs(node.right, curSum) lookup[curSum] -= 1 dfs(root, 0) return self.ans
https://leetcode.com/problems/binary-tree-paths/
class Solution: def binaryTreePaths(self, root: Optional[TreeNode]) -> List[str]: ans = [] def dfs(node, temp): if node is None: return [] if node.left == None and node.right == None: return ans.append(temp + str(node.val)) temp += str(node.val) + "->" dfs(node.left, temp) dfs(node.right, temp) dfs(root, "") return ans
https://leetcode.com/problems/smallest-string-starting-from-leaf/
class Solution: def smallestFromLeaf(self, root: Optional[TreeNode]) -> str: self.ans = 'z' + chr(1) def dfs(node, s): if node == None: return s += chr(ord('a') + node.val) if node.left == None and node.right == None: self.ans = min(self.ans, s[::-1]) dfs(node.left, s) dfs(node.right, s) s = s[:-1] dfs(root, "") return self.ans
https://leetcode.com/problems/diameter-of-binary-tree/
class Solution: def diameterOfBinaryTree(self, root: Optional[TreeNode]) -> int: self.ans = 0 def dfs(root): if root == None: return 0 l, r = dfs(root.left), dfs(root.right) self.ans = max((l + r), self.ans) return max(l, r) + 1 dfs(root) return self.ans
https://leetcode.com/problems/binary-tree-maximum-path-sum/
class Solution: def maxPathSum(self, root: Optional[TreeNode]) -> int: self.ans = float('-inf') def dfs(node): if node == None: return 0 l, r = dfs(node.left), dfs(node.right) self.ans = max(self.ans, l + r + node.val) return max(0, max(l, r) + node.val) dfs(root) return self.ans
https://leetcode.com/problems/longest-univalue-path/
class Solution: def longestUnivaluePath(self, root: Optional[TreeNode]) -> int: self.ans = 0 def dfs(node): if node == None: return 0 l, r = dfs(node.left), dfs(node.right) L, R = 0, 0 if node.left != None and node.left.val == node.val: L = l if node.right != None and node.right.val == node.val: R = r self.ans = max(self.ans, L + R) return max(L, R) + 1 dfs(root) return self.ans
https://leetcode.com/problems/n-ary-tree-preorder-traversal/
class Solution: def preorder(self, root: 'Node') -> List[int]: self.ans = [] def dfs(node): if node == None: return self.ans.append(node.val) for child in node.children: dfs(child) dfs(root) return self.ans
https://leetcode.com/problems/n-ary-tree-postorder-traversal/
class Solution: def postorder(self, root: 'Node') -> List[int]: self.ans = [] def dfs(node): if node == None: return for child in node.children: dfs(child) self.ans.append(node.val) dfs(root) return self.ans
https://leetcode.com/problems/minimum-depth-of-binary-tree/
class Solution: def minDepth(self, root: Optional[TreeNode]) -> int: self.ans = float("inf") if root == None: return 0 def dfs(node, dep): if node == None: return 0 if node.left == None and node.right == None: self.ans = min(self.ans, dep) dfs(node.left, dep + 1) dfs(node.right, dep + 1) dfs(root, 1) return self.ans
https://leetcode.com/problems/balanced-binary-tree/
class Solution: def isBalanced(self, root: Optional[TreeNode]) -> bool: def dfs(node): if node == None: return 0 l, r = dfs(node.left), dfs(node.right) if l == -1: return -1 if r == -1: return -1 if abs(l - r) > 1: return -1 return max(l, r) + 1 return dfs(root) != -1
https://leetcode.com/problems/increasing-order-search-tree/
class Solution: def increasingBST(self, root: TreeNode) -> TreeNode: dummy = TreeNode(-1) self.cur = dummy def dfs(node): if node == None: return dfs(node.left) self.cur.right = node node.left = None self.cur = self.cur.right dfs(node.right) dfs(root) return dummy.right
https://leetcode.com/problems/sum-of-left-leaves/
class Solution: def sumOfLeftLeaves(self, root: Optional[TreeNode]) -> int: self.ans = 0 def dfs(node): if node == None: return 0 if node.left != None and node.left.left == None and node.left.right == None: self.ans += node.left.val dfs(node.left) dfs(node.right) dfs(root) return self.ans
https://leetcode.com/problems/binary-tree-pruning/
class Solution: def pruneTree(self, root: Optional[TreeNode]) -> Optional[TreeNode]: def dfs(node): if not node: return False l, r = dfs(node.left), dfs(node.right) if not l: node.left = None if not r: node.right = None return l or r or node.val == 1 return root if dfs(root) else None
https://leetcode.com/problems/binary-tree-longest-consecutive-sequence/
class Solution: def longestConsecutive(self, root: Optional[TreeNode]) -> int: self.max = 1 def dfs(node, cnt): self.max = max(self.max, cnt) if node.left: if node.left.val == node.val + 1: dfs(node.left, cnt + 1) else: dfs(node.left, 1) if node.right: if node.right.val == node.val + 1: dfs(node.right, cnt + 1) else: dfs(node.right, 1) dfs(root, 1) return self.max
https://leetcode.com/problems/binary-tree-longest-consecutive-sequence-ii/
class Solution: def longestConsecutive(self, root: Optional[TreeNode]) -> int: self.max = 0 def dfs(node): if node == None: return [0, 0] l, r = dfs(node.left), dfs(node.right) inc, dec = 1, 1 if node.left: if node.val == node.left.val + 1: dec = l[1] + 1 if node.val == node.left.val - 1: inc = l[0] + 1 if node.right: if node.val == node.right.val + 1: dec = max(dec, r[1] + 1) if node.val == node.right.val - 1: inc = max(inc, r[0] + 1) self.max = max(self.max, inc + dec - 1) return [inc, dec] dfs(root) return self.max
https://leetcode.com/problems/maximum-width-of-binary-tree/
class Solution: def widthOfBinaryTree(self, root: Optional[TreeNode]) -> int: self.max = 0 pos = [] def dfs(node, dep, p): if node == None: return if dep == len(pos): pos.append(p) self.max = max(self.max, p - pos[dep] + 1) dfs(node.left, dep + 1, p * 2 + 1) dfs(node.right, dep + 1, p * 2 + 2) dfs(root, 0, 0) return self.max
https://leetcode.com/problems/maximum-product-of-splitted-binary-tree/
class Solution: def maxProduct(self, root: Optional[TreeNode]) -> int: self.total = 0 self.ans = 0 def dfs1(node): if node == None: return self.total += node.val dfs1(node.left) dfs1(node.right) def dfs2(node): if node == None: return 0 l, r = dfs2(node.left), dfs2(node.right) self.ans = max(self.ans, max(l * (self.total - l), r * (self.total - r))) return node.val + l + r dfs1(root) dfs2(root) return self.ans % (10 ** 9 + 7)
https://leetcode.com/problems/find-mode-in-binary-search-tree/
class Solution: def findMode(self, root: Optional[TreeNode]) -> List[int]: self.pre = root.val self.cur, self.max = 0, 0 self.ans = [] def dfs(node): if node == None: return dfs(node.left) if node.val != self.pre: self.cur = 1 self.pre = node.val else: self.cur += 1 if self.cur > self.max: self.max = self.cur self.ans.clear() self.ans.append(node.val) elif self.cur == self.max: self.ans.append(node.val) dfs(node.right) dfs(root) return self.ans
https://leetcode.com/problems/convert-sorted-array-to-binary-search-tree/
class Solution: def sortedArrayToBST(self, nums: List[int]) -> Optional[TreeNode]: def dfs(left, right): if left > right: return None mid = (left + right) // 2 root = TreeNode(nums[mid]) root.left = dfs(left, mid - 1) root.right = dfs(mid + 1, right) return root return dfs(0, len(nums) - 1)
https://leetcode.com/problems/kth-smallest-element-in-a-bst/
class Solution: def kthSmallest(self, root: Optional[TreeNode], k: int) -> int: self.ans = None self.k = k def dfs(node): if node is None: return dfs(node.left) self.k -= 1 if self.k == 0: self.ans = node.val return dfs(node.right) dfs(root) return self.ans
https://leetcode.com/problems/recover-binary-search-tree/
class Solution: def recoverTree(self, root: Optional[TreeNode]) -> None: arr = [] def dfs(node): if node == None: return dfs(node.left) arr.append(node) dfs(node.right) dfs(root) a = None b = None for i in range(0, len(arr)): if arr[i].val > arr[i + 1].val: a = arr[i] break for i in range(len(arr) - 1, -1, -1): if arr[i].val < arr[i - 1].val: b = arr[i] break a.val, b.val = b.val, a.val
https://leetcode.com/problems/inorder-successor-in-bst/
class Solution: def inorderSuccessor(self, root: TreeNode, p: TreeNode) -> Optional[TreeNode]: self.ans = None self.flag = False def dfs(node): if node == None: return dfs(node.left) if self.flag and self.ans == None: self.ans = node if not self.flag and node == p: self.flag = True dfs(node.right) dfs(root) return self.ans
https://leetcode.com/problems/closest-binary-search-tree-value-ii/
class Solution: def closestKValues(self, root: Optional[TreeNode], target: float, k: int) -> List[int]: self.q = deque() def dfs(node): if node == None: return dfs(node.left) if len(self.q) < k: self.q.append(node.val) elif abs(self.q[0] - target) > abs(node.val - target): self.q.popleft() self.q.append(node.val) dfs(node.right) dfs(root) return self.q
https://leetcode.com/problems/generate-parentheses/
class Solution: def generateParenthesis(self, n: int) -> List[str]: def dfs(u, l, r, cur): if u == 2 * n: return ans.append(cur) if r < l: dfs(u + 1, l, r + 1, cur + ")") if l < n: dfs(u + 1, l + 1, r, cur + "(") ans = [] dfs(0, 0, 0, "") return ans
https://leetcode.com/problems/throne-inheritance/
class ThroneInheritance: def __init__(self, kingName: str): self.g = defaultdict(list) self.kingName = kingName self.dead = set() def birth(self, parentName: str, childName: str) -> None: self.g[parentName].append(childName) def death(self, name: str) -> None: self.dead.add(name) def getInheritanceOrder(self) -> List[str]: def dfs(u): if u not in self.dead: ans.append(u) for v in self.g[u]: dfs(v) ans = [] dfs(self.kingName) return ans
https://leetcode.com/problems/number-of-enclaves/
class Solution: def numEnclaves(self, grid: List[List[int]]) -> int: def dfs(i, j): grid[i][j] = 0 for ni, nj in [(i - 1, j), (i + 1, j), (i, j - 1), (i, j + 1)]: if 0 <= ni < m and 0 <= nj < n and grid[ni][nj] == 1: dfs(ni, nj) m, n = len(grid), len(grid[0]) for i in range(m): for j in range(n): if grid[i][j] == 1 and (i == 0 or j == 0 or i == m - 1 or j == n - 1): dfs(i, j) return sum(sum(row) for row in grid)
https://leetcode.com/problems/validate-binary-tree-nodes/
class Solution: def validateBinaryTreeNodes(self, n: int, leftChild: List[int], rightChild: List[int]) -> bool: def dfs(u): vis.add(u) if leftChild[u] != -1: if leftChild[u] in vis or not dfs(leftChild[u]): return False if rightChild[u] != -1: if rightChild[u] in vis or not dfs(rightChild[u]): return False return True d = [0] * n for x in leftChild + rightChild: if x != -1: d[x] += 1 if d[x] > 1: return False if d.count(0) != 1: return False root = d.index(0) vis = set() if not dfs(root): return False return len(vis) == n
https://leetcode.com/problems/number-of-islands/
class Solution: def numIslands(self, grid: List[List[str]]) -> int: def dfs(i, j): grid[i][j] = '0' for ni, nj in [(i - 1, j), (i + 1, j), (i, j - 1), (i, j + 1)]: if 0 <= ni < m and 0 <= nj < n and grid[ni][nj] == '1': dfs(ni, nj) ans = 0 m, n = len(grid), len(grid[0]) for i in range(m): for j in range(n): if grid[i][j] == '1': ans += 1 dfs(i, j) return ans
https://leetcode.com/problems/count-sub-islands/
class Solution: def countSubIslands(self, grid1: List[List[int]], grid2: List[List[int]]) -> int: def dfs(i, j): nonlocal isSub grid2[i][j] = 0 if grid1[i][j] == 0: isSub = False for ni, nj in [(i - 1, j), (i + 1, j), (i, j - 1), (i, j + 1)]: if 0 <= ni < m and 0 <= nj < n and grid2[ni][nj] == 1: dfs(ni, nj) ans = 0 m, n = len(grid1), len(grid1[0]) for i in range(m): for j in range(n): if grid2[i][j] == 1: isSub = True dfs(i, j) if isSub: ans += 1 return ans
https://leetcode.com/problems/count-servers-that-communicate/
class Solution: def countServers(self, grid: List[List[int]]) -> int: def dfs(i, j): nonlocal cnt cnt += 1 vis.add((i, j)) for ni, nj in g1[i] + g2[j]: if (ni, nj) not in vis: dfs(ni, nj) g1 = defaultdict(list) g2 = defaultdict(list) m, n = len(grid), len(grid[0]) for i in range(m): for j in range(n): if grid[i][j] == 1: g1[i].append([i, j]) g2[j].append([i, j]) vis = set() ans = 0 for i in range(m): for j in range(n): if grid[i][j] == 1 and (i, j) not in vis: cnt = 0 dfs(i, j) if cnt > 1: ans += cnt return ans
https://leetcode.com/problems/word-search/
class Solution: def exist(self, board: List[List[str]], word: str) -> bool: def dfs(i, j, u): if board[i][j] != word[u]: return False if u == len(word) - 1: return True t = board[i][j] board[i][j] = '#' for ni, nj in [(i - 1, j), (i + 1, j), (i, j - 1), (i, j + 1)]: if 0 <= ni < m and 0 <= nj < n and board[ni][nj] != '#': if dfs(ni, nj, u + 1): return True board[i][j] = t return False m, n = len(board), len(board[0]) for i in range(m): for j in range(n): if dfs(i, j, 0): return True return False
https://leetcode.com/problems/surrounded-regions/
class Solution: def solve(self, board: List[List[str]]) -> None: def dfs(i, j): board[i][j] = '#' for ni, nj in [(i - 1, j), (i + 1, j), (i, j - 1), (i, j + 1)]: if 0 <= ni < m and 0 <= nj < n and board[ni][nj] == 'O': dfs(ni, nj) m, n = len(board), len(board[0]) for i in range(m): for j in range(n): if (i == 0 or j == 0 or i == m - 1 or j == n - 1) and board[i][j] == 'O': dfs(i, j) for i in range(m): for j in range(n): if board[i][j] == '#': board[i][j] = 'O' elif board[i][j] == 'O': board[i][j] = 'X'
https://leetcode.com/problems/clone-graph/
class Solution: def cloneGraph(self, node: 'Node') -> 'Node': def dfs(node): if node is None: return None if node not in d: d[node] = Node(node.val) for v in node.neighbors: d[node].neighbors.append(dfs(v)) return d[node] d = {} return dfs(node)
https://leetcode.com/problems/number-of-connected-components-in-an-undirected-graph/
class Solution: def countComponents(self, n: int, edges: List[List[int]]) -> int: def dfs(u): vis.add(u) for v in g[u]: if v not in vis: dfs(v) ans = 0 g = defaultdict(list) vis = set() for u, v in edges: g[u].append(v) g[v].append(u) for i in range(n): if i not in vis: ans += 1 dfs(i) return ans
https://leetcode.com/problems/pacific-atlantic-water-flow/
class Solution: def pacificAtlantic(self, heights: List[List[int]]) -> List[List[int]]: def dfs(i, j, h): h.add((i, j)) for ni, nj in [(i - 1, j), (i + 1, j), (i, j - 1), (i, j + 1)]: if 0 <= ni < m and 0 <= nj < n and heights[ni][nj] >= heights[i][j] and (ni, nj) not in h: dfs(ni, nj, h) m, n = len(heights), len(heights[0]) h1, h2 = set(), set() for i in range(m): for j in range(n): if i == 0 or j == 0: dfs(i, j, h1) if i == m - 1 or j == n - 1: dfs(i, j, h2) return list(h1 & h2)
https://leetcode.com/problems/the-maze/
class Solution: def hasPath(self, maze: List[List[int]], start: List[int], destination: List[int]) -> bool: def dfs(i, j): if [i, j] == destination: return True vis.add((i, j)) for d in [(-1, 0), (1, 0), (0, -1), (0, 1)]: ni, nj = i, j while 0 <= ni + d[0] < m and 0 <= nj + d[1] < n and maze[ni + d[0]][nj + d[1]] == 0: ni, nj = ni + d[0], nj + d[1] if (ni, nj) not in vis and dfs(ni, nj): return True return False m, n = len(maze), len(maze[0]) vis = set() return dfs(start[0], start[1])
https://leetcode.com/problems/number-of-distinct-islands/
class Solution: def numDistinctIslands(self, grid: List[List[int]]) -> int: def dfs(i, j): nonlocal path grid[i][j] = 0 for ni, nj, d in [(i - 1, j, 'u'), (i + 1, j, 'd'), (i, j - 1, 'l'), (i, j + 1, 'r')]: path += d if 0 <= ni < m and 0 <= nj < n and grid[ni][nj] == 1: dfs(ni, nj) m, n = len(grid), len(grid[0]) ans = set() for i in range(m): for j in range(n): if grid[i][j] == 1: path = '' dfs(i, j) ans.add(path) return len(ans)
https://leetcode.com/problems/max-area-of-island/
class Solution: def maxAreaOfIsland(self, grid: List[List[int]]) -> int: def dfs(i, j): nonlocal cnt grid[i][j] = 0 cnt += 1 for ni, nj in [(i - 1, j), (i + 1, j), (i, j - 1), (i, j + 1)]: if 0 <= ni < m and 0 <= nj < n and grid[ni][nj] == 1: dfs(ni, nj) ans = 0 m, n = len(grid), len(grid[0]) for i in range(m): for j in range(n): if grid[i][j] == 1: cnt = 0 dfs(i, j) ans = max(cnt, ans) return ans
https://leetcode.com/problems/keys-and-rooms/
class Solution: def canVisitAllRooms(self, rooms: List[List[int]]) -> bool: def dfs(u): vis.add(u) for v in rooms[u]: if v not in vis: dfs(v) vis = set() dfs(0) return len(vis) == len(rooms)
https://leetcode.com/problems/nested-list-weight-sum/
class Solution: def depthSum(self, nestedList: List[NestedInteger]) -> int: def dfs(cur, dep): nonlocal ans for x in cur: if x.isInteger(): ans += dep * x.getInteger() else: dfs(x.getList(), dep + 1) ans = 0 dfs(nestedList, 1) return ans
https://leetcode.com/problems/employee-importance/
class Solution: def getImportance(self, employees: List['Employee'], id: int) -> int: def dfs(u): nonlocal ans ans += d[u].importance for v in d[u].subordinates: dfs(v) ans = 0 d = {} for e in employees: d[e.id] = e dfs(id) return ans
https://leetcode.com/problems/all-paths-from-source-to-target/
class Solution: def allPathsSourceTarget(self, graph: List[List[int]]) -> List[List[int]]: def dfs(u, path): nonlocal ans path.append(u) if u == len(graph) - 1: ans.append(path[::]) for v in graph[u]: dfs(v, path) path.pop() ans = [] dfs(0, []) return ans
https://leetcode.com/problems/jump-game-iii/
class Solution: def canReach(self, arr: List[int], start: int) -> bool: def dfs(i): if arr[i] == 0: return True vis.add(i) ans = False if i + arr[i] < len(arr) and i + arr[i] not in vis: ans |= dfs(i + arr[i]) if i - arr[i] >= 0 and i - arr[i] not in vis: ans |= dfs(i - arr[i]) return ans vis = set() return dfs(start)
https://leetcode.com/problems/number-of-closed-islands/
class Solution: def closedIsland(self, grid: List[List[int]]) -> int: def dfs(i, j): grid[i][j] = 1 for ni, nj in [(i - 1, j), (i + 1, j), (i, j - 1), (i, j + 1)]: if 0 <= ni < m and 0 <= nj < n and grid[ni][nj] == 0: dfs(ni, nj) m, n = len(grid), len(grid[0]) for i in range(m): for j in range(n): if (i == 0 or j == 0 or i == m - 1 or j == n - 1) and grid[i][j] == 0: dfs(i, j) ans = 0 for i in range(m): for j in range(n): if grid[i][j] == 0: ans += 1 dfs(i, j) return ans
https://leetcode.com/problems/reorder-routes-to-make-all-paths-lead-to-the-city-zero/
class Solution: def minReorder(self, n: int, connections: List[List[int]]) -> int: def dfs(u): nonlocal ans vis.add(u) for v in g[u]: if v not in vis: if (u, v) not in origin: ans += 1 dfs(v) origin = set((u, v) for u, v in connections) g = defaultdict(list) for u, v in connections: g[u].append(v) g[v].append(u) ans = 0 vis = set() dfs(0) return len(connections) - ans
https://leetcode.com/problems/number-of-operations-to-make-network-connected/
class Solution: def makeConnected(self, n: int, connections: List[List[int]]) -> int: def dfs(u): vis.add(u) for v in g[u]: if v not in vis: dfs(v) if len(connections) < n - 1: return -1 g = defaultdict(list) for u, v in connections: g[u].append(v) g[v].append(u) ans = 0 vis = set() for i in range(n): if i not in vis: ans += 1 dfs(i) return ans - 1
https://leetcode.com/problems/possible-bipartition/
class Solution: def possibleBipartition(self, n: int, dislikes: List[List[int]]) -> bool: def dfs(u, c): if u in color: return color[u] == c color[u] = c for v in g[u]: if not dfs(v, c ^ 1): return False return True color = {} g = defaultdict(list) for u, v in dislikes: g[u].append(v) g[v].append(u) for i in range(1, n + 1): if i not in color and not dfs(i, 0): return False return True
https://leetcode.com/problems/kill-process/
class Solution: def killProcess(self, pid: List[int], ppid: List[int], kill: int) -> List[int]: def dfs(u): ans.append(u) for v in g[u]: dfs(v) n = len(pid) g = defaultdict(list) for i in range(n): g[ppid[i]].append(pid[i]) ans = [] dfs(kill) return ans
https://leetcode.com/problems/time-needed-to-inform-all-employees/
class Solution: def numOfMinutes(self, n: int, headID: int, manager: List[int], informTime: List[int]) -> int: def dfs(u, time): nonlocal ans ans = max(ans, time) for v in g[u]: dfs(v, time + informTime[u]) ans = 0 g = defaultdict(list) for i in range(n): g[manager[i]].append(i) dfs(headID, 0) return ans
https://leetcode.com/problems/lexicographical-numbers/
class Solution: def lexicalOrder(self, n: int) -> List[int]: def dfs(u): for i in range(1 if u == 0 else 0, min(9, n) + 1): if u + i <= n: ans.append(u + i) if (u + i) * 10 <= n: dfs((u + i) * 10) ans = [] dfs(0) return ans
https://leetcode.com/problems/most-stones-removed-with-same-row-or-column/
class Solution: def removeStones(self, stones: List[List[int]]) -> int: def dfs(r, c): vis.add((r, c)) for nr, nc in g1[r] + g2[c]: if (nr, nc) not in vis: dfs(nr, nc) g1 = defaultdict(list) g2 = defaultdict(list) for r, c in stones: g1[r].append([r, c]) g2[c].append([r, c]) ans = 0 vis = set() for r, c in stones: if (r, c) not in vis: ans += 1 dfs(r, c) return len(stones) - ans
https://leetcode.com/problems/sentence-similarity-ii/
class Solution: def areSentencesSimilarTwo(self, sentence1: List[str], sentence2: List[str], similarPairs: List[List[str]]) -> bool: def dfs(u, target): if u == target: return True vis.add(u) for v in g[u]: if v not in vis and dfs(v, target): return True return False if len(sentence1) != len(sentence2): return False g = defaultdict(list) for u, v in similarPairs: g[u].append(v) g[v].append(u) for u, v in zip(sentence1, sentence2): vis = set() if not dfs(u, v): return False return True
https://leetcode.com/problems/evaluate-division/
class Solution: def calcEquation(self, equations: List[List[str]], values: List[float], queries: List[List[str]]) -> List[float]: def dfs(x, y, i, cur): if x == y: ans[i] = cur return vis.add(x) for z, val in g[x]: if z not in vis: dfs(z, y, i, cur * val) g = defaultdict(list) for (x, y), z in zip(equations, values): g[x].append((y, z)) g[y].append((x, 1/z)) ans = [-1] * len(queries) for i, (x, y) in enumerate(queries): vis = set() if x in g and y in g: dfs(x, y, i, 1) return ans
https://leetcode.com/problems/letter-combinations-of-a-phone-number/
class Solution: def letterCombinations(self, digits: str) -> List[str]: if digits == "": return [] d = { "2": "abc", "3": "def", "4": "ghi", "5": "jkl", "6": "mno", "7": "pqrs", "8": "tuv", "9": "wxyz" } ans = [] def dfs(cur, j): if j == len(digits): return ans.append(cur) for v in d[digits[j]]: dfs(cur + str(v), j + 1) dfs("", 0) return ans
https://leetcode.com/problems/unique-paths-iii/
class Solution: def uniquePathsIII(self, grid: List[List[int]]) -> int: def dfs(i, j): nonlocal ans if i == er and j == ec: if len(vis) + 1 == m * n - block: ans += 1 return vis.add((i, j)) for ni, nj in [(i - 1, j), (i + 1, j), (i, j - 1), (i, j + 1)]: if 0 <= ni < m and 0 <= nj < n and grid[ni][nj] != -1 and (ni, nj) not in vis: dfs(ni, nj) vis.remove((i, j)) ans = 0 vis = set() block = 0 sr, sc, er, ec = 0, 0, 0, 0 m, n = len(grid), len(grid[0]) for i in range(m): for j in range(n): if grid[i][j] == 1: sr, sc = i, j if grid[i][j] == 2: er, ec = i, j if grid[i][j] == -1: block += 1 dfs(sr, sc) return ans
https://leetcode.com/problems/is-graph-bipartite/
class Solution: def isBipartite(self, graph: List[List[int]]) -> bool: def dfs(u, c): if u in vis: return vis[u] == c vis[u] = c for v in graph[u]: if not dfs(v, c ^ 1): return False return True vis = {} n = len(graph) for i in range(n): if i not in vis: if not dfs(i, 0): return False return True
https://leetcode.com/problems/coloring-a-border/
class Solution: def colorBorder(self, grid: List[List[int]], row: int, col: int, color: int) -> List[List[int]]: def dfs(i, j): t[i][j] = True grid[i][j] = color for ni, nj in [(i - 1, j), (i + 1, j), (i, j - 1), (i, j + 1)]: if 0 <= ni < m and 0 <= nj < n and grid[ni][nj] == old: dfs(ni, nj) if grid[row][col] == color: return grid m, n = len(grid), len(grid[0]) old = grid[row][col] t = [[False] * n for _ in range(m)] dfs(row, col) for i in range(1, m - 1): for j in range(1, n - 1): if t[i][j] and t[i - 1][j] and t[i + 1][j] and t[i][j - 1] and t[i][j + 1]: grid[i][j] = old return grid
https://leetcode.com/problems/detect-cycles-in-2d-grid/
class Solution: def containsCycle(self, grid: List[List[str]]) -> bool: def dfs(i, j, pi, pj): vis.add((i, j)) for ni, nj in [(i-1, j), (i + 1, j), (i, j - 1), (i, j + 1)]: if 0 <= ni < m and 0 <= nj < n and grid[ni][nj] == grid[i][j] and (ni, nj) != (pi, pj): if (ni, nj) in vis or dfs(ni, nj, i, j): return True return False m, n = len(grid), len(grid[0]) vis = set() for i in range(m): for j in range(n): if (i, j) not in vis: if dfs(i, j, -1, -1): return True return False
https://leetcode.com/problems/shortest-bridge/
class Solution: def shortestBridge(self, grid: List[List[int]]) -> int: def dfs(i, j): heapq.heappush(q, (0, i, j)) vis.add((i, j)) for ni, nj in [(i - 1, j), (i + 1, j), (i, j - 1), (i, j + 1)]: if 0 <= ni < m and 0 <= nj < n and grid[ni][nj] == 1 and (ni, nj) not in vis: dfs(ni, nj) def bfs(): while q: x, i, j = heapq.heappop(q) if x > 0 and grid[i][j] == 1: return x - 1 for ni, nj in [(i - 1, j), (i + 1, j), (i, j - 1), (i, j + 1)]: if 0 <= ni < m and 0 <= nj < n and (ni, nj) not in vis: vis.add((ni, nj)) heapq.heappush(q, (x + 1, ni, nj)) m, n = len(grid), len(grid[0]) q = [] for i in range(m): for j in range(n): if grid[i][j] == 1: vis = set() dfs(i, j) return bfs()
https://leetcode.com/problems/minesweeper/
class Solution: def updateBoard(self, board: List[List[str]], click: List[int]) -> List[List[str]]: def dfs(i, j): cnt = 0 for d in dirs: ni, nj = i + d[0], j + d[1] if 0 <= ni < m and 0 <= nj < n and board[ni][nj] == 'M': cnt += 1 if cnt == 0: board[i][j] = 'B' for d in dirs: ni, nj = i + d[0], j + d[1] if 0 <= ni < m and 0 <= nj < n and board[ni][nj] == 'E': dfs(ni, nj) else: board[i][j] = str(cnt) dirs = [(-1, -1), (-1, 0), (-1, 1), (0, -1), (0, 1), (1, -1), (1, 0), (1, 1)] m, n = len(board), len(board[0]) i, j = click if board[i][j] == 'M': board[i][j] = 'X' else: dfs(i, j) return board
https://leetcode.com/problems/number-of-provinces/
class Solution: def findCircleNum(self, isConnected: List[List[int]]) -> int: def dfs(i): vis.add(i) for j in range(n): if isConnected[i][j] and j not in vis: dfs(j) ans = 0 n = len(isConnected) vis = set() for i in range(n): if i not in vis: dfs(i) ans += 1 return ans
https://leetcode.com/problems/all-paths-from-source-lead-to-destination/
class Solution: def leadsToDestination(self, n: int, edges: List[List[int]], source: int, destination: int) -> bool: @lru_cache(None) def dfs(u): if not g[u]: return u == destination vis.add(u) for v in g[u]: if v in vis or not dfs(v): return False vis.remove(u) return True vis = set() g = defaultdict(list) for u, v in edges: g[u].append(v) return dfs(source)
https://leetcode.com/problems/smallest-common-region/
class Solution: def findSmallestRegion(self, regions: List[List[str]], region1: str, region2: str) -> str: def dfs(u): if u == region1 or u == region2: return u ans = set() for v in g[u]: t = dfs(v) if t: ans.add(t) if len(ans) == 2: return u return ans.pop() if len(ans) == 1 else None g = defaultdict(list) sub = set() for region in regions: for i in range(1, len(region)): g[region[0]].append(region[i]) sub.add(region[i]) for region in regions: if region[0] not in sub: return dfs(region[0])
https://leetcode.com/problems/regions-cut-by-slashes/
class Solution: def regionsBySlashes(self, grid: List[str]) -> int: def dfs(i, j): g[i][j] = 1 for ni, nj in [(i - 1, j), (i + 1, j), (i, j - 1), (i, j + 1)]: if 0 <= ni < m * 3 and 0 <= nj < n * 3 and g[ni][nj] == 0: dfs(ni, nj) m, n = len(grid), len(grid[0]) g = [[0] * n * 3 for _ in range(m * 3)] for i in range(m): for j in range(n): if grid[i][j] == '/': for k in range(3): g[i * 3 + k][j * 3 + 2 - k] = 1 elif grid[i][j] == '\\': for k in range(3): g[i * 3 + k][j * 3 + k] = 1 ans = 0 for i in range(m * 3): for j in range(n * 3): if g[i][j] == 0: ans += 1 dfs(i, j) return ans
https://leetcode.com/problems/pyramid-transition-matrix/
class Solution: def pyramidTransition(self, bottom: str, allowed: List[str]) -> bool: @lru_cache(None) def dfs(s, i): if len(s) == 1: return True if i == len(s) - 1: return dfs(s[:-1], 0) for c in g[s[i: i + 2]]: if dfs(s[:i] + c + s[i + 1:], i + 1): return True return False g = defaultdict(list) for s in allowed: g[s[:2]].append(s[-1]) return dfs(bottom, 0)
https://leetcode.com/problems/loud-and-rich/
class Solution: def loudAndRich(self, richer: List[List[int]], quiet: List[int]) -> List[int]: @lru_cache(None) def dfs(u): if not g[u]: return [quiet[u], u] t = min(dfs(v) for v in g[u]) t = min(t, [quiet[u], u]) if quiet[ans[u]] > quiet[t[1]]: ans[u] = t[1] return t n = len(quiet) ans = list(range(n)) g = defaultdict(list) for u, v in richer: g[v].append(u) for i in range(n): dfs(i) return ans
https://leetcode.com/problems/check-if-there-is-a-valid-path-in-a-grid/
class Solution: def hasValidPath(self, grid: List[List[int]]) -> bool: def dfs(i, j, d): if i == m - 1 and j == n - 1: return True vis.add((i, j)) ni, nj = i + dirs[d][0], j + dirs[d][1] if 0 <= ni < m and 0 <= nj < n and (ni, nj) not in vis and g[grid[ni][nj]][d] != -1: if dfs(ni, nj, g[grid[ni][nj]][d]): return True return False # 0 up 1 right 2 down 3 left g = [[], [-1, 1, -1, 3], [0, -1, 2, -1], [3, 2, -1, -1], [1, -1, -1, 2], [-1, 0, 3, -1], [-1, -1, 1, 0]] m, n = len(grid), len(grid[0]) vis = set() dirs = [[-1, 0], [0, 1], [1, 0], [0, -1]] for i in range(4): if dfs(0, 0, i): return True return False
https://leetcode.com/problems/flower-planting-with-no-adjacent/
class Solution: def gardenNoAdj(self, n: int, paths: List[List[int]]) -> List[int]: ans = [0] * n g = defaultdict(list) for u, v in paths: g[u - 1].append(v - 1) g[v - 1].append(u - 1) for i in range(n): ans[i] = ({1, 2, 3, 4} - {ans[j] for j in g[i]}).pop() return ans
https://leetcode.com/problems/nested-list-weight-sum-ii/
class Solution: def depthSumInverse(self, nestedList: List[NestedInteger]) -> int: def getDep(cur, u): nonlocal mx mx = max(mx, u) for v in cur: if not v.isInteger() and v.getList(): getDep(v.getList(), u + 1) def dfs(cur, u): nonlocal ans for v in cur: if v.isInteger(): ans += v.getInteger() * (mx - u + 1) else: dfs(v.getList(), u + 1) mx = 0 getDep(nestedList, 1) ans = 0 dfs(nestedList, 1) return ans
• BFS
https://leetcode.com/problems/letter-combinations-of-a-phone-number/
class Solution: def letterCombinations(self, digits: str) -> List[str]: if digits == "": return [] s = ["", "", "abc", "def", "ghi", "jkl", "mno", "pqrs", "tuv", "wxyz" ] a = [""] for c in digits: b = [] for cur in a: for ch in s[int(c)]: b.append(cur + ch) a = b return a
https://leetcode.com/problems/brace-expansion/
class Solution: def expand(self, s: str) -> List[str]: n = len(s) a = [''] i = 0 while i < n: b = [] if s[i] == '{': j = s.find('}', i) t = [c for c in s[i + 1: j] if c.isalpha()] i = j + 1 else: t = s[i] i = i + 1 for c in t: for cur in a: b.append(cur + c) a = b return sorted(a)
https://leetcode.com/problems/rotting-oranges/
class Solution: def orangesRotting(self, grid: List[List[int]]) -> int: q = deque() m, n = len(grid), len(grid[0]) for i in range(m): for j in range(n): if grid[i][j] == 2: q.append([i, j, 0]) time = 0 while q: x, y, time = q.popleft() for nx, ny in [(x - 1, y), (x + 1, y), (x, y - 1), (x, y + 1)]: if 0 <= nx < m and 0 <= ny < n and grid[nx][ny] == 1: grid[nx][ny] = 2 q.append([nx, ny, time + 1]) for g in grid: if 1 in g: return -1 return time
https://leetcode.com/problems/shortest-path-to-get-food/
class Solution: def getFood(self, grid: List[List[str]]) -> int: m, n = len(grid), len(grid[0]) vis = set() q = deque() for i in range(m): for j in range(n): if grid[i][j] == 'X': vis.add((i, j)) elif grid[i][j] == '*': vis.add((i, j)) q.append((i, j, 0)) while q: i, j, k = q.popleft() if grid[i][j] == '#': return k for ni, nj in [(i - 1, j), (i + 1, j), (i, j - 1), (i, j + 1)]: if 0 <= ni < m and 0 <= nj < n and (ni, nj) not in vis: vis.add((ni, nj)) q.append((ni, nj, k + 1)) return -1
https://leetcode.com/problems/minimum-knight-moves/
class Solution: def minKnightMoves(self, x: int, y: int) -> int: dirs = [[-2, 1], [-1, 2], [1, 2], [2, 1], [2, -1], [1, -2], [-1, -2], [-2, -1]] q = deque() vis = set() q.append((0, 0, 0)) while q: i, j, k = q.popleft() if i == x and j == y: return k for a, b in dirs: ni, nj = i + a, j + b if (ni, nj) not in vis: vis.add((ni, nj)) q.append((ni, nj, k + 1))
https://leetcode.com/problems/nearest-exit-from-entrance-in-maze/
class Solution: def nearestExit(self, maze: List[List[str]], entrance: List[int]) -> int: m, n = len(maze), len(maze[0]) q = deque() q.append((entrance[0], entrance[1], 0)) vis = {(entrance[0], entrance[1])} while q: i, j, k = q.popleft() if (i == 0 or j == 0 or i == m - 1 or j == n - 1) and [i, j] != entrance: return k for ni, nj in [(i - 1, j), (i + 1, j), (i, j - 1), (i, j + 1)]: if 0 <= ni < m and 0 <= nj < n and (ni, nj) not in vis and maze[ni][nj] == '.': q.append((ni, nj, k + 1)) vis.add((ni, nj)) return -1
https://leetcode.com/problems/minimum-operations-to-convert-number/
class Solution: def minimumOperations(self, nums: List[int], start: int, goal: int) -> int: q = deque() q.append((start, 0)) vis = {start} while q: u, k = q.popleft() if u == goal: return k for x in nums: for v in [u + x, u - x, u ^ x]: if v == goal: return k + 1 if 0 <= v <= 1000 and v not in vis: q.append((v, k + 1)) vis.add(v) return -1
https://leetcode.com/problems/01-matrix/
class Solution: def updateMatrix(self, mat: List[List[int]]) -> List[List[int]]: m, n = len(mat), len(mat[0]) g = [[0] * n for _ in range(m)] q = deque() vis = set() for i in range(m): for j in range(n): if mat[i][j] == 0: vis.add((i, j)) q.append((i, j, 0)) while q: i, j, k = q.popleft() for ni, nj in [(i - 1, j), (i + 1, j), (i, j - 1), (i, j + 1)]: if 0 <= ni < m and 0 <= nj < n and (ni, nj) not in vis: vis.add((ni, nj)) q.append((ni, nj, k + 1)) g[ni][nj] = k + 1 return g
https://leetcode.com/problems/map-of-highest-peak/
class Solution: def highestPeak(self, isWater: List[List[int]]) -> List[List[int]]: m, n = len(isWater), len(isWater[0]) g = [[0] * n for _ in range(m)] q = deque() vis = set() for i in range(m): for j in range(n): if isWater[i][j] == 1: q.append((i, j, 0)) vis.add((i, j)) while q: i, j, k = q.popleft() for ni, nj in [(i - 1, j), (i + 1, j), (i, j - 1), (i, j + 1)]: if 0 <= ni < m and 0 <= nj < n and (ni, nj) not in vis: g[ni][nj] = k + 1 q.append((ni, nj, k + 1)) vis.add((ni, nj)) return g
https://leetcode.com/problems/walls-and-gates/
class Solution: def wallsAndGates(self, rooms: List[List[int]]) -> None: m, n = len(rooms), len(rooms[0]) q = deque() vis = set() for i in range(m): for j in range(n): if rooms[i][j] == 0: vis.add((i, j)) q.append((i, j, 0)) elif rooms[i][j] == -1: vis.add((i, j)) while q: i, j, k = q.popleft() for ni, nj in [(i - 1, j), (i + 1, j), (i, j - 1), (i, j + 1)]: if 0 <= ni < m and 0 <= nj < n and (ni, nj) not in vis: vis.add((ni, nj)) q.append((ni, nj, k + 1)) rooms[ni][nj] = k + 1
https://leetcode.com/problems/as-far-from-land-as-possible/
class Solution: def maxDistance(self, grid: List[List[int]]) -> int: m, n = len(grid), len(grid[0]) q = deque() vis = set() for i in range(m): for j in range(n): if grid[i][j] == 1: q.append((i, j, 0)) vis.add((i, j)) ans = -1 while q: i, j, k = q.popleft() if grid[i][j] == 0: ans = max(ans, k) for ni, nj in [(i - 1, j), (i + 1, j), (i, j - 1), (i, j + 1)]: if 0 <= ni < m and 0 <= nj < n and (ni, nj) not in vis: q.append((ni, nj, k + 1)) vis.add((ni, nj)) return ans
https://leetcode.com/problems/minimum-genetic-mutation/
class Solution: def minMutation(self, start: str, end: str, bank: List[str]) -> int: q = deque() q.append((start, 0)) vis = set() vis.add(start) bank = set(bank) if end in vis: return -1 while q: s, k = q.popleft() if s == end: return k s = list(s) for i in range(8): t = s[i] for c in {'A', 'C', 'G', 'T'} - {t}: s[i] = c ns = ''.join(s) if ns not in vis and ns in bank: vis.add(ns) q.append((ns, k + 1)) s[i] = t return -1
https://leetcode.com/problems/all-nodes-distance-k-in-binary-tree/
class Solution: def distanceK(self, root: TreeNode, target: TreeNode, k: int) -> List[int]: def build(root, p): par[root] = p if root.left: build(root.left, root) if root.right: build(root.right, root) par = defaultdict(TreeNode) build(root, None) ans = [] q = deque() q.append([target, 0]) vis = {target} while q: cur, step = q.popleft() if step == k: ans.append(cur.val) continue if cur.left and cur.left not in vis: q.append([cur.left, step + 1]) vis.add(cur.left) if cur.right and cur.right not in vis: q.append([cur.right, step + 1]) vis.add(cur.right) if par[cur] and par[cur] not in vis: q.append([par[cur], step + 1]) vis.add(par[cur]) return ans
https://leetcode.com/problems/snakes-and-ladders/
class Solution: def snakesAndLadders(self, board: List[List[int]]) -> int: def pos(x): r, c = (x - 1) // n, (x - 1) % n if r % 2 == 1: c = n - 1 - c return (n - 1 - r, c) n = len(board) q = deque() q.append([1, 0]) vis = {1} if board[n - 1][0] == n * n: return 1 while q: x, k = q.popleft() if x == n * n: return k for i in range(1, 7): nx = x + i ni, nj = pos(nx) if nx <= n * n: if board[ni][nj] != -1: nx = board[ni][nj] if nx not in vis: vis.add(nx) q.append([nx, k + 1]) return -1
https://leetcode.com/problems/web-crawler/
class Solution: def crawl(self, startUrl: str, htmlParser: 'HtmlParser') -> List[str]: p = startUrl.find('/', 7) host = startUrl if p == -1 else startUrl[ : p] a = [startUrl] ans = {startUrl} while a: b = [] for s in a: for url in htmlParser.getUrls(s): if url not in ans and url.startswith(host): ans.add(url) b.append(url) a = b return list(ans)
https://leetcode.com/problems/water-and-jug-problem/
class Solution: def canMeasureWater(self, x: int, y: int, t: int) -> bool: q = deque() q.append((x, y, 0)) vis = {(x, y)} while q: a, b, k = q.popleft() if a + b == t: return True for na, nb in [(x, b), (a, y), (0, b), (a, 0), (min(x, a + b), max(0, a + b - x)), (max(0, a + b - y), min(y, a + b))]: if (na, nb) not in vis: q.append((na, nb, k + 1)) vis.add((na, nb)) return False
https://leetcode.com/problems/get-watched-videos-by-your-friends/
class Solution: def watchedVideosByFriends(self, watchedVideos: List[List[str]], friends: List[List[int]], id: int, level: int) -> List[str]: ans = Counter() q = deque() q.append((id, 0)) vis = {id} while q: u, k = q.popleft() if k == level: ans += Counter(watchedVideos[u]) continue for v in friends[u]: if v not in vis: vis.add(v) q.append((v, k + 1)) return [k for k, v in sorted(ans.items(), key = lambda x: (x[1], x[0]))]
https://leetcode.com/problems/shortest-path-with-alternating-colors/
class Solution: def shortestAlternatingPaths(self, n: int, redEdges: List[List[int]], blueEdges: List[List[int]]) -> List[int]: red, blue = defaultdict(list), defaultdict(list) for u, v in redEdges: red[u].append(v) for u, v in blueEdges: blue[u].append(v) ans = [-1] * n q = deque() q.append((0, '', 0)) redVis, blueVis = {0}, {0} while q: u, c, k = q.popleft() if ans[u] == -1 or ans[u] > k: ans[u] = k if c != 'r': for v in red[u]: if v not in redVis: q.append((v, 'r', k + 1)) redVis.add(v) if c != 'b': for v in blue[u]: if v not in blueVis: q.append((v, 'b', k + 1)) blueVis.add(v) return ans
https://leetcode.com/problems/open-the-lock/
class Solution: def openLock(self, deadends: List[str], target: str) -> int: vis = set(deadends) if '0000' in vis: return -1 q = deque() q.append(('0000', 0)) vis.add('0000') while q: s, k = q.popleft() if s == target: return k for d in [-1, 1]: s = list(s) for i in range(4): t = s[i] s[i] = str((int(s[i]) + d) % 10) ns = ''.join(s) if ns not in vis: vis.add(ns) q.append((ns, k + 1)) s[i] = t return -1
https://leetcode.com/problems/stepping-numbers/
class Solution: def countSteppingNumbers(self, low: int, high: int) -> List[int]: ans = [] if low == 0: ans.append(0) q = deque() for i in range(1, min(10, high + 1)): q.append(i) while q: u = q.popleft() if u > high: break if u >= low: ans.append(u) if u % 10 - 1 >= 0: q.append(u * 10 + u % 10 - 1) if u % 10 + 1 <= 9: q.append(u * 10 + u % 10 + 1) return ans
https://leetcode.com/problems/numbers-with-same-consecutive-differences/
class Solution: def numsSameConsecDiff(self, n: int, k: int) -> List[int]: ans = [] a = [_ for _ in range(1, 10)] while a: b = [] for x in a: if len(str(x)) == n: ans.append(x) continue if k == 0: a.append(x * 10 + x % 10) else: if x % 10 - k >= 0: a.append(x * 10 + x % 10 - k) if x % 10 + k <= 9: a.append(x * 10 + x % 10 + k) a = b return ans
https://leetcode.com/problems/minimum-jumps-to-reach-home/
class Solution: def minimumJumps(self, forbidden: List[int], a: int, b: int, x: int) -> int: q = deque() q.append((0, 1, 0)) vis = {(0, 1)} for v in forbidden: vis.add((v, 0)) vis.add((v, 1)) while q: p, back, k = q.popleft() if p == x: return k if p + a <= 6005 and (p + a, 1) not in vis: q.append((p + a, 1, k + 1)) vis.add((p + a, 1)) if back and p - b >= 0 and (p - b, 0) not in vis: q.append((p - b, 0, k + 1)) vis.add((p - b, 0)) return -1