《算法通关之路》-chapter4深搜和广搜

《算法通关之路》学习笔记,记录一下自己的刷题过程,详细的内容请大家购买作者的书籍查阅。

路径总和 II

力扣第113题
给你二叉树的根节点 root 和一个整数目标和 targetSum ,找出所有 从根节点到叶子节点 路径总和等于给定目标和的路径。
叶子节点 是指没有子节点的节点。

from typing import Optional
class TreeNode:
    def __init__(self, val=0, left=None, right=None):
        self.val = val
        self.left = left
        self.right = right

'''
方法一:dfs递归
时间复杂度:O(n)
空间复杂度:最好情况 O(logn)
'''
class Solution:
    def pathSum(self, root: Optional[TreeNode], targetSum: int) -> list[list[int]]:
        res = []

        def dfs(root: TreeNode, targetSum: int, path: list):
            if not root:
                return
            if not root.left and not root. right and targetSum - root.val == 0:
                path += [root.val]
                res.append(path)
            dfs(root.left, targetSum - root.val, path + [root.val])
            dfs(root.right, targetSum - root.val, path + [root.val])
        
        dfs(root, targetSum, [])
        return res

二叉树中的最大路径和

力扣第124题
二叉树中的 路径 被定义为一条节点序列,序列中每对相邻节点之间都存在一条边。同一个节点在一条路径序列中 至多出现一次 。该路径 至少包含一个 节点,且不一定经过根节点。
路径和 是路径中各节点值的总和。
给你一个二叉树的根节点 root ,返回其 最大路径和 。

'''
方法一:dfs递归
时间复杂度:O(n)
空间复杂度:最好情况 O(logn)
'''
class Solution:
    def maxPathSum(self, root: Optional[TreeNode]) -> int:
        max_sum = float('-inf')
        
        def dfs(root: TreeNode):
            nonlocal max_sum
            if not root:
                return 0
            max_left = max(dfs(root.left), 0)
            max_right = max(dfs(root.right), 0)
            max_sum = max(max_sum, max_left + max_right + root.val) # 当前层计算当前层最大路径并保留
            return root.val + max(max_left, max_right) # 向上返回根节点+左右子树中路径大的一边
        
        dfs(root)
        return max_sum

岛屿数量

力扣第200题
给你一个由 ‘1’(陆地)和 ‘0’(水)组成的的二维网格,请你计算网格中岛屿的数量。
岛屿总是被水包围,并且每座岛屿只能由水平方向和/或竖直方向上相邻的陆地连接形成。
此外,你可以假设该网格的四条边均被水包围。

'''
方法一:dfs递归
时间复杂度:O(mn)
空间复杂度:最坏情况 O(mn)
'''
class Solution:
    def numIslands(self, grid: list[list[str]]) -> int:
        m, n = len(grid), len(grid[0])
        cnt = 0

        def dfs(r, c):
            grid[r][c] = '0'
            if c < n - 1 and grid[r][c+1] == '1':
                dfs(r, c + 1)
            if c > 0 and grid[r][c-1] == '1':
                dfs(r, c - 1)
            if r > 0 and grid[r-1][c] == '1':
                dfs(r-1, c)
            if r + 1 < m and grid[r+1][c] == '1':
                dfs(r+1, c)
        
        for i in range(m):
            for j in range(n):
                if grid[i][j] == '1':
                    dfs(i, j)
                    cnt += 1
        
        return cnt

# 试运行
grid = [
  ["1","1","1","1","0"],
  ["1","1","0","1","0"],
  ["1","1","0","0","0"],
  ["0","0","0","0","0"]
]

solu = Solution()
solu.numIslands(grid)
'''
方法二:dfs迭代
时间复杂度:O(mn)
空间复杂度:最坏情况 O(mn)
'''
class Solution:
    def numIslands(self, grid: list[list[str]]) -> int:
        m, n = len(grid), len(grid[0])
        cnt = 0

        def dfs(r, c):
            grid[r][c] = '0'
            stack = [[r, c]]
            while stack:
                r, c = stack[-1]
                if c < n - 1 and grid[r][c+1] == '1':
                    stack.append([r, c+1])
                    grid[r][c+1] = '0'
                    continue
                if c > 0 and grid[r][c-1] == '1':
                    stack.append([r, c-1])
                    grid[r][c-1] = '0'
                    continue
                if r > 0 and grid[r-1][c] == '1':
                    stack.append([r-1, c])
                    grid[r-1][c] = '0'
                    continue
                if r + 1 < m and grid[r+1][c] == '1':
                    stack.append([r+1, c])
                    grid[r+1][c] = '0'
                    continue
                stack.pop()
        
        for i in range(m):
            for j in range(n):
                if grid[i][j] == '1':
                    dfs(i, j)
                    cnt += 1
        
        return cnt

# 试运行
grid = [
  ["1","1","1","1","0"],
  ["1","1","0","1","0"],
  ["1","1","0","0","0"],
  ["0","0","0","0","0"]
]

solu = Solution()
solu.numIslands(grid)
'''
方法三:bfs
时间复杂度:O(mn)
空间复杂度:最坏情况 O(mn)
'''
class Solution:
    def numIslands(self, grid: list[list[str]]) -> int:
        m, n = len(grid), len(grid[0])
        cnt = 0

        def bfs(r, c):
            grid[r][c] = '0'
            queue = [[r, c]]
            while queue:
                r, c = queue.pop(0)
                if c < n - 1 and grid[r][c+1] == '1':
                    queue.append([r, c+1])
                    grid[r][c+1] = '0'
                if c > 0 and grid[r][c-1] == '1':
                    queue.append([r, c-1])
                    grid[r][c-1] = '0'
                if r > 0 and grid[r-1][c] == '1':
                    queue.append([r-1, c])
                    grid[r-1][c] = '0'
                if r + 1 < m and grid[r+1][c] == '1':
                    queue.append([r+1, c])
                    grid[r+1][c] = '0'
        
        for i in range(m):
            for j in range(n):
                if grid[i][j] == '1':
                    bfs(i, j)
                    cnt += 1
        
        return cnt
    
# 试运行
grid = [
  ["1","1","1","1","0"],
  ["1","1","0","1","0"],
  ["1","1","0","0","0"],
  ["0","0","0","0","0"]
]

solu = Solution()
solu.numIslands(grid)
'''
方法四:并查集
时间复杂度:O(mn×α(mn))
空间复杂度:O(mn)
'''
class UnionFind:
    def __init__(self, grid):
        m, n = len(grid), len(grid[0])
        self.count = 0
        self.parent = [-1] * (m * n)
        self.rank = [0] * (m * n)
        for i in range(m):
            for j in range(n):
                if grid[i][j] == "1":
                    self.parent[i * n + j] = i * n + j
                    self.count += 1
    
    def find(self, i):
        if self.parent[i] != i:
            self.parent[i] = self.find(self.parent[i])
        return self.parent[i]
    
    def union(self, x, y):
        rootx = self.find(x)
        rooty = self.find(y)
        if rootx != rooty:
            if self.rank[rootx] < self.rank[rooty]:
                rootx, rooty = rooty, rootx
            self.parent[rooty] = rootx
            if self.rank[rootx] == self.rank[rooty]:
                self.rank[rootx] += 1
            self.count -= 1
    
    def getCount(self):
        return self.count

class Solution:
    def numIslands(self, grid: list[list[str]]) -> int:
        nr, nc = len(grid), len(grid[0])
        uf = UnionFind(grid)

        for r in range(nr):
            for c in range(nc):
                if grid[r][c] == "1":
                    grid[r][c] = "0"
                    for x, y in [(r - 1, c), (r + 1, c), (r, c - 1), (r, c + 1)]:
                        if 0 <= x < nr and 0 <= y < nc and grid[x][y] == "1":
                            uf.union(r * nc + c, x * nc + y)
        
        return uf.getCount()

# 试运行
grid = [
  ["1","1","1","1","0"],
  ["1","1","0","1","0"],
  ["1","1","0","0","0"],
  ["0","0","0","0","0"]
]

solu = Solution()
solu.numIslands(grid)

岛屿数量 II

力扣第305题
给你一个大小为 m x n 的二进制网格 grid 。网格表示一个地图,其中,0 表示水,1 表示陆地。最初,grid 中的所有单元格都是水单元格(即,所有单元格都是 0)。
可以通过执行 addLand 操作,将某个位置的水转换成陆地。给你一个数组 positions ,其中 positions[i] = [ri, ci] 是要执行第 i 次操作的位置 (ri, ci) 。
返回一个整数数组 answer ,其中 answer[i] 是将单元格 (ri, ci) 转换为陆地后,地图中岛屿的数量。
岛屿 的定义是被「水」包围的「陆地」,通过水平方向或者垂直方向上相邻的陆地连接而成。你可以假设地图网格的四边均被无边无际的「水」所包围。

'''
方法一:并查集
时间复杂度:O(klog(mn))
空间复杂度:O(mn)
'''
class UnionFind:
    def __init__(self, grid):
        m, n = len(grid), len(grid[0])
        self.count = 0
        self.parent = [0] * (m * n)
        self.rank = [0] * (m * n)
    
    def find(self, i):
        if self.parent[i] != i:
            self.parent[i] = self.find(self.parent[i])
        return self.parent[i]
    
    def union(self, x, y):
        rootx = self.find(x)
        rooty = self.find(y)
        if rootx != rooty:
            if self.rank[rootx] < self.rank[rooty]:
                rootx, rooty = rooty, rootx
            self.parent[rooty] = rootx
            if self.rank[rootx] == self.rank[rooty]:
                self.rank[rootx] += 1
            self.count -= 1
    
    def getCount(self):
        return self.count
    
    def setCount(self, count):
        self.count = count
    
    def setParent(self, i, val):
        self.parent[i] = val

class Solution:
    def numIslands2(self, m: int, n: int, positions: list[list[int]]) -> list[int]:
        answer = []
        grid = [[0] * n for _ in range(m)]
        uf = UnionFind(grid)
        for row, col in positions:
            if grid[row][col] == 0:
                uf.setCount(uf.getCount() + 1)
                uf.setParent(row * n + col, row * n + col)
                grid[row][col] = 1
                if row > 0 and grid[row-1][col] == 1:
                    uf.union(row*n+col, (row-1)*n+col)
                if row + 1 < m and grid[row+1][col] == 1:
                    uf.union(row*n+col, (row+1)*n+col)
                if col > 0 and grid[row][col-1] == 1:
                    uf.union(row*n+col, row*n+col-1)
                if col + 1 < n and grid[row][col+1] == 1:
                    uf.union(row*n+col, row*n+col+1)
            answer.append(uf.getCount())
        return answer

m, n, positions =  3, 3, [[0,0],[0,1],[1,2],[2,1]]
solu = Solution()
solu.numIslands2(m, n, positions)

Github笔记本

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Jiawen9

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值