# CSPT21 Lecture 14 ## [All Paths From Source to Target](https://leetcode.com/problems/all-paths-from-source-to-target/) ``` from collections import deque class Solution: """ Plan 1. Translate the problem into graph terminology vertices - each index in the list edges - each element in the sublist is an outgoing edge of that node at index i weight - n/a 2. Build your graph - You can build your own graph using an adjacency list - OR you can just traverse the nested list 3. Traverse the graph traversal doesn't matter since we're looking for all possible paths use a DFS use an auxilliary array and also put it in the stack to keep track of the path to get to the current node [[1,2], [3], [3], []] """ def allPathsSourceTarget(self, graph: List[List[int]]) -> List[List[int]]: res = [] self.allPathsSourceTargetHelper(graph, 0, len(graph) - 1, [0], res) return res def allPathsSourceTargetHelper(self, graph, currNode, destinationNode, currPath, res): if currNode == destinationNode: res.append(currPath) else: for neighbor in graph[currNode]: newPath = currPath.copy() newPath.append(neighbor) self.allPathsSourceTargetHelper(graph, neighbor, destinationNode, newPath, res) def bfsAllPathsSourceTarget(self, graph: List[List[int]]) -> List[List[int]]: destinationNode = len(graph) - 1 queue = deque() queue.append((0, [0])) res = [] while len(queue) > 0: curr = queue.popleft() currNode, currPath = curr[0], curr[1] if currNode == destinationNode: res.append(currPath) else: for neighbor in graph[currNode]: newPath = currPath.copy() newPath.append(neighbor) queue.append((neighbor, newPath)) return res def implicitAllPathsSourceTarget(self, graph: List[List[int]]) -> List[List[int]]: destinationNode = len(graph) - 1 stack = deque() stack.append((0, [0])) res = [] while len(stack) > 0: curr = stack.pop() currNode, currPath = curr[0], curr[1] if currNode == destinationNode: res.append(currPath) else: for neighbor in graph[currNode]: newPath = currPath.copy() newPath.append(neighbor) stack.append((neighbor, newPath)) return res def explicitAllPathsSourceTarget(self, graph: List[List[int]]) -> List[List[int]]: destinationNode = len(graph) - 1 graph = self.buildGraph(graph) stack = deque() stack.append((0, [0])) res = [] while len(stack) > 0: curr = stack.pop() currNode, currPath = curr[0], curr[1] if currNode == destinationNode: res.append(currPath) else: for neighbor in graph[currNode]: newPath = currPath.copy() newPath.append(neighbor) stack.append((neighbor, newPath)) return res def buildGraph(self, edges): graph = {} for (node, neighbors) in enumerate(edges): graph[node] = set() for neighbor in neighbors: graph[node].add(neighbor) return graph ``` ## [Flood Fill](https://leetcode.com/problems/flood-fill/) ``` from collections import deque class Solution: """ [[2,2,2], [2,2,0], [2,0,1]] Plan 1. Translate the problem into graph terminology vertices - pixel edges - neighboring pixels weight - n/a 2. Build your graph No need to build a graph, just traverse the image given 3. Traverse the graph It doesn't matter, as long as you traverse all the neighboring pixels that have the same value as the starting pixel [[0,0,0], [0,1*,1]] 1 1 1 """ def floodFill(self, image: List[List[int]], sr: int, sc: int, newColor: int) -> List[List[int]]: visited = set() self.floodFillHelper(image, sr, sc, image[sr][sc], newColor, visited) return image def floodFillHelper(self, image, currRow, currCol, colorToChange, newColor, visited): numRows, numCols = len(image), len(image[0]) if currRow < 0 or currRow >= numRows or currCol < 0 or currCol >= numCols: return if image[currRow][currCol] != colorToChange: return if (currRow, currCol) in visited: return image[currRow][currCol] = newColor visited.add((currRow, currCol)) self.floodFillHelper(image, currRow - 1, currCol, colorToChange, newColor, visited) self.floodFillHelper(image, currRow + 1, currCol, colorToChange, newColor, visited) self.floodFillHelper(image, currRow, currCol - 1, colorToChange, newColor, visited) self.floodFillHelper(image, currRow, currCol + 1, colorToChange, newColor, visited) def bftFloodFill(self, image: List[List[int]], sr: int, sc: int, newColor: int) -> List[List[int]]: colorToChange = image[sr][sc] queue = deque() queue.append((sr, sc)) numRows, numCols = len(image), len(image[0]) visited = set() while len(queue) > 0: currPixel = queue.popleft() if currPixel in visited: continue currRow, currCol = currPixel[0], currPixel[1] image[currRow][currCol] = newColor visited.add(currPixel) topRow = currRow - 1 if topRow >= 0 and image[topRow][currCol] == colorToChange: queue.append((topRow, currCol)) bottomRow = currRow + 1 if bottomRow < numRows and image[bottomRow][currCol] == colorToChange: queue.append((bottomRow, currCol)) leftCol = currCol - 1 if leftCol >= 0 and image[currRow][leftCol] == colorToChange: queue.append((currRow, leftCol)) rightCol = currCol + 1 if rightCol < numCols and image[currRow][rightCol] == colorToChange: queue.append((currRow, rightCol)) return image def dftFloodFill(self, image: List[List[int]], sr: int, sc: int, newColor: int) -> List[List[int]]: colorToChange = image[sr][sc] stack = deque() stack.append((sr, sc)) numRows, numCols = len(image), len(image[0]) visited = set() while len(stack) > 0: currPixel = stack.pop() if currPixel in visited: continue currRow, currCol = currPixel[0], currPixel[1] image[currRow][currCol] = newColor visited.add(currPixel) topRow = currRow - 1 if topRow >= 0 and image[topRow][currCol] == colorToChange: stack.append((topRow, currCol)) bottomRow = currRow + 1 if bottomRow < numRows and image[bottomRow][currCol] == colorToChange: stack.append((bottomRow, currCol)) leftCol = currCol - 1 if leftCol >= 0 and image[currRow][leftCol] == colorToChange: stack.append((currRow, leftCol)) rightCol = currCol + 1 if rightCol < numCols and image[currRow][rightCol] == colorToChange: stack.append((currRow, rightCol)) return image ```