导语
leetcode刷题笔记记录,本篇博客是贪心部分的第6期,主要记录题目包括:
Leetcode 738. 单调递增的数字
题目描述
当且仅当每个相邻位数上的数字 x 和 y 满足 x <= y 时,我们称这个整数是单调递增的。
给定一个整数 n ,返回 小于或等于 n 的最大数字,且数字呈 单调递增 。
示例 1:
输入: n = 10
输出: 9
示例 2:
输入: n = 1234
输出: 1234
提示:
0 <= n <= 109
解法
本题使用贪心算法,以98为例,一旦出现strNum[i - 1] > strNum[i]的情况(非单调递增),首先想让strNum[i - 1]减一,strNum[i]赋值9,这样这个整数就是89。就可以很自然想到对应的贪心解法了。想到了贪心,还要考虑遍历顺序,只有从后向前遍历才能重复利用上次比较的结果。
class Solution:
def monotoneIncreasingDigits(self, n: int) -> int:
# 将整数 n 转换为字符列表,便于之后的处理
string = list(str(n))
# 初始化 flag,它用于记录第一个不符合单调递增条件的位置
flag = len(string)
# 从右到左遍历字符列表
for i in range(len(string)-1, 0, -1):
# 如果当前位置的数字小于它左边的数字,即它们不满足单调递增的条件
if string[i] < string[i-1]:
# 将左边的数字减一
string[i-1] = str(int(string[i-1])-1)
# 更新 flag 为当前位置
flag = i
# 从 flag 开始,将其右边的所有数字都设置为9
for i in range(flag, len(string)):
string[i] = '9'
# 将修改后的字符列表转回整数并返回
return int("".join(string))
Leetcode 968. 监控二叉树
题目描述
给定一个二叉树,我们在树的节点上安装摄像头。节点上的每个摄影头都可以监视其父对象、自身及其直接子对象。 计算监控树的所有节点所需的最小摄像头数量。
示例 1:
输入: [0,0,null,0,0]
输出: 1
解释: 如图所示,一台摄像头足以监控所有节点。
示例 2:
输入: [0,0,null,0,null,0,null,null,0]
输出: 2
解释: 需要至少两个摄像头来监视树的所有节点。 上图显示了摄像头放置的有效位置之一。
提示:
- 给定树的节点数的范围是
[1, 1000]。 - 每个节点的值都是 0。
解法
这是一个涉及到树结构和贪心的问题。为了找到需要的最小摄像头数量,可以使用递归的后序遍历方式从叶子到根来解决这个问题。
思路:
-
对于树的每个节点,我们有三种状态:
- 0:此节点未被覆盖
- 1:此节点已被摄像头覆盖,但此节点上没有摄像头
- 2:此节点上放置了摄像头
-
通过后序遍历,我们首先考虑子节点,然后确定当前节点的状态。
-
状态转移:
- 如果左或右子节点未被覆盖(状态为0),那么当前节点必须放置摄像头,状态变为2。
- 如果左或右子节点放置了摄像头(状态为2),那么当前节点被摄像头覆盖,状态变为1。
- 否则,当前节点的状态为0,表示它未被覆盖。
-
我们从树的叶子开始向上遍历,直到遍历到根。这样可以保证每个节点都是在其子节点之后被考虑的。
class Solution:
def __init__(self):
# 初始化摄像头数量为0
self.result = 0
def traversal(self, cur):
# 后序遍历当前节点
# 定义三种状态:0:未覆盖;1:有摄像头;2:已覆盖但没有摄像头;
# 如果当前节点为空,返回已被覆盖状态
# 这是因为叶子节点外部不需要摄像头覆盖
if cur == None:
return 2
# 递归遍历左子节点,并获取其状态
left = self.traversal(cur.left)
# 递归遍历右子节点,并获取其状态
right = self.traversal(cur.right)
# 如果左右子节点都已被覆盖,但没有摄像头
# 当前节点没有被覆盖
if left == 2 and right == 2:
return 0
# 如果左或右子节点没有被覆盖
# 在当前节点上放置一个摄像头
# 并更新摄像头的数量
if left == 0 or right == 0:
self.result += 1
return 1
# 如果左或右子节点有摄像头
# 则当前节点已被覆盖但没有摄像头
if left == 1 or right == 1:
return 2
# 该返回值在代码中未被使用,表示未定义的状态
return -1
def minCameraCover(self, root: Optional[TreeNode]) -> int:
# 重新初始化摄像头数量为0
self.result = 0
# 开始从根节点遍历整棵树
# 如果根节点未被覆盖,再增加一个摄像头
if self.traversal(root) == 0:
self.result += 1
# 返回所需的摄像头数量
return self.result