代码随想录算法训练营第三十七天 | 贪心算法 part 6 | 738.单调递增的数字、968.监控二叉树、总结

本文介绍了LeetCode中的两道题目:738.单调递增的数字,使用贪心策略求解,以及968.监控二叉树,通过状态转移判断节点是否需安装摄像头。详细分析了两种算法的时间和空间复杂度。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

738.单调递增的数字

Leetcode

在这里插入图片描述

思路

这一道题使用的贪心思路是:

  1. 首先将数字变成字符串
  2. 从后往前遍历每个位数的数字
  3. 一旦出现strNum[i - 1] > strNum[i]的情况(非单调递增),让strNum[i - 1]减一, strNum[i] = 9
  4. 局部最优会引向全局最优

代码

卡哥的代码使用了flag来记录需要更换成9的digit的位置,这样能省得在for loop里面直接改。

class Solution:
    def monotoneIncreasingDigits(self, n: int) -> int:
        strN = str(n)
        flag = len(strN)

        for i in range(len(strN) - 1, 0, -1):
            if int(strN[i-1]) > int(strN[i]):
                flag = i
                strN = strN[:i-1] + str(int(strN[i-1]) - 1) + strN[i:]

        for i in range(flag, len(strN)):
            strN = strN[:i] + '9' + strN[i+1:]
        return int(strN)

复杂度分析

  • 时间复杂度:O(n)n 为数字长度
  • 空间复杂度:O(n),需要一个字符串,转化为字符串操作更方便

968.监控二叉树

Leetcode

在这里插入图片描述

思路

这道题对节点的不同状态分为三种:

0 -> 无覆盖
1 -> 有摄像头
2 -> 有覆盖

通过对状态的推导和转移来确定该节点是否为摄像头节点。

具体的细节可以看

链接

代码

我写的

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def minCameraCover(self, root: Optional[TreeNode]) -> int:
        res = 0
        def dfs(cur):
            nonlocal res 

            if not cur:
                return 2
            
            left = dfs(cur.left)
            right = dfs(cur.right)

            if left == 2 and right == 2:
                return 0

            if left == 0 or right == 0:
                res += 1
                return 1

            if left == 1 or right == 1:
                return 2
        
        if dfs(root) == 0:
            res += 1
        return res

卡哥的注释代码

class Solution:
         # Greedy Algo:
        # 从下往上安装摄像头:跳过leaves这样安装数量最少,局部最优 -> 全局最优
        # 先给leaves的父节点安装,然后每隔两层节点安装一个摄像头,直到Head
        # 0: 该节点未覆盖
        # 1: 该节点有摄像头
        # 2: 该节点有覆盖
    def minCameraCover(self, root: TreeNode) -> int:
        # 定义递归函数
        result = [0]  # 用于记录摄像头的安装数量
        if self.traversal(root, result) == 0:
            result[0] += 1

        return result[0]

        
    def traversal(self, cur: TreeNode, result: List[int]) -> int:
        if not cur:
            return 2

        left = self.traversal(cur.left, result)
        right = self.traversal(cur.right, result)

        # 情况1: 左右节点都有覆盖
        if left == 2 and right == 2:
            return 0

        # 情况2:
        # left == 0 && right == 0 左右节点无覆盖
        # left == 1 && right == 0 左节点有摄像头,右节点无覆盖
        # left == 0 && right == 1 左节点无覆盖,右节点有摄像头
        # left == 0 && right == 2 左节点无覆盖,右节点覆盖
        # left == 2 && right == 0 左节点覆盖,右节点无覆盖
        if left == 0 or right == 0:
            result[0] += 1
            return 1

        # 情况3:
        # left == 1 && right == 2 左节点有摄像头,右节点有覆盖
        # left == 2 && right == 1 左节点有覆盖,右节点有摄像头
        # left == 1 && right == 1 左右节点都有摄像头
        if left == 1 or right == 1:
            return 2

总结

套用卡哥知识星球其中一位成员:海螺人的总结图

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值