代码随想录算法训练营Day 36 || 738.单调递增的数字、968.监控二叉树

738.单调递增的数字

力扣题目链接(opens new window)

给定一个非负整数 N,找出小于或等于 N 的最大的整数,同时这个整数需要满足其各个位数上的数字是单调递增。

(当且仅当每个相邻位数上的数字 x 和 y 满足 x <= y 时,我们称这个整数是单调递增的。)

示例 1:

  • 输入: N = 10
  • 输出: 9

示例 2:

  • 输入: N = 1234
  • 输出: 1234

示例 3:

  • 输入: N = 332
  • 输出: 299

说明: N 是在 [0, 10^9] 范围内的一个整数。

class Solution:
    def monotoneIncreasingDigits(self, n: int) -> int:
        digits = [int(d) for d in str(n)]
        length = len(digits)
        
        # 从右往左遍历,找到第一个不满足单调递增条件的位置
        for i in range(length - 1, 0, -1):
            if digits[i] < digits[i - 1]:
                # 将当前位置减1
                digits[i - 1] -= 1
                # 将当前位置之后的所有数字都设置为9,以确保最大性
                for j in range(i, length):
                    digits[j] = 9
        
        # 将列表中的数字组合成整数
        result = 0
        for d in digits:
            result = result * 10 + d
        
        return result

# 示例
solution = Solution()
N1 = 10
N2 = 1234
N3 = 332

print(solution.monotoneIncreasingDigits(N1))  # 输出: 9
print(solution.monotoneIncreasingDigits(N2))  # 输出: 1234
print(solution.monotoneIncreasingDigits(N3))  # 输出: 299

968.监控二叉树

力扣题目链接(opens new window)

给定一个二叉树,我们在树的节点上安装摄像头。

节点上的每个摄影头都可以监视其父对象、自身及其直接子对象。

计算监控树的所有节点所需的最小摄像头数量。

示例 1:

代码随想录算法训练营Day 36 || 738.单调递增的数字、968.监控二叉树_第1张图片

  • 输入:[0,0,null,0,0]
  • 输出:1
  • 解释:如图所示,一台摄像头足以监控所有节点。

示例 2:

代码随想录算法训练营Day 36 || 738.单调递增的数字、968.监控二叉树_第2张图片

  • 输入:[0,0,null,0,null,0,null,null,0]
  • 输出:2
  • 解释:需要至少两个摄像头来监视树的所有节点。 上图显示了摄像头放置的有效位置之一。

提示:

  • 给定树的节点数的范围是 [1, 1000]。
  • 每个节点的值都是 0。

 

from typing import Optional

class TreeNode:
    def __init__(self, x):
        self.val = x
        self.left = None
        self.right = None

class Solution:
    def minCameraCover(self, root: Optional[TreeNode]) -> int:
        # 定义三种状态
        UNCOVERED, COVERED, MONITORED = 0, 1, 2
        
        def dfs(node):
            if not node:
                return COVERED, 0  # 空节点不需要摄像头,且已经被覆盖
            left_status, left_cameras = dfs(node.left)
            right_status, right_cameras = dfs(node.right)
            
            # 如果左右子节点有一个未被覆盖,当前节点需要放置摄像头
            if left_status == UNCOVERED or right_status == UNCOVERED:
                return MONITORED, left_cameras + right_cameras + 1
            # 如果左右子节点有一个放置了摄像头,当前节点被覆盖
            elif left_status == MONITORED or right_status == MONITORED:
                return COVERED, left_cameras + right_cameras
            # 其他情况,当前节点未被覆盖
            else:
                return UNCOVERED, left_cameras + right_cameras
        
        status, cameras = dfs(root)
        # 如果根节点未被覆盖,还需要加一个摄像头
        return cameras + (status == UNCOVERED)

首先,我们定义了三个状态:

  • UNCOVERED: 这意味着该节点没有被摄像头覆盖。
  • COVERED: 这意味着该节点被摄像头覆盖,但是该节点上没有摄像头。
  • MONITORED: 这意味着该节点上有一个摄像头,它可以覆盖其父节点和子节点。

我们的目标是使用尽可能少的摄像头来覆盖整棵树。

下面是代码的逻辑解释:

  1. 如果当前的节点是空的,则它自动被认为是COVERED,因为我们不需要在空节点上放摄像头。

  2. 我们递归地处理左子节点和右子节点,然后根据子节点的状态来决定当前节点的状态。

  3. 如果左子节点或右子节点中的任何一个是UNCOVERED,这意味着当前节点必须有一个摄像头,因为只有当前节点上的摄像头才能覆盖这些UNCOVERED的子节点。所以,我们设置当前节点的状态为MONITORED

  4. 如果左子节点或右子节点中的任何一个是MONITORED,这意味着当前节点已经被覆盖了,但是不需要在上面放摄像头,因为它的子节点已经有摄像头了。所以,我们设置当前节点的状态为COVERED

  5. 否则,这意味着左右子节点都是COVERED而没有摄像头。这时,当前节点是UNCOVERED

  6. 当整个树处理完毕后,如果根节点仍然是UNCOVERED,我们需要再加一个摄像头。

你可能感兴趣的:(leetcode,leetcode)