题目链接:56. 合并区间 - 力扣(LeetCode)
思考:本题需要对有重叠区间进行合并,最终结果存放多个无重叠的区间。首先对原始数组按照区间左边界由小到大排序,这样便于从左到右遍历区间。
每次结果保存的都是一个区间,只有当无重叠的情况才会保存该区间,这个被保存的区间需要随着遍历更新,因此初始化left和right为数组的第一个区间的左右边界。
相邻两个区间不重叠时,前面的区间就可以被保存下来,然后left和right就切换为下一个区间的左右边界。
相邻两个区间重叠时,新的左边界是两个区间左边界的最小值,新的右边界是两个区间右边界的最大值。
有一个特殊情况,那就是遍历到最后一个区间的时候,不论最后一个区间与前一个区间是否有重叠,left和right都会被更新,而这个结果还没有保存。因此遍历结束后,需要再保存一下[left, right]这个区间。
代码:
class Solution:
def merge(self, intervals: List[List[int]]) -> List[List[int]]:
n = len(intervals)
intervals.sort(key=lambda x: x[0])
res = []
left = intervals[0][0]
right = intervals[0][1]
for i in range(1,n):
if intervals[i][0] > right: # 无重叠
res.append([left, right])
left = intervals[i][0]
right = intervals[i][1]
else:
# 有重叠
left = min(left, intervals[i][0])
right = max(right, intervals[i][1])
res.append([left, right])
return res
题目链接:738. 单调递增的数字 - 力扣(LeetCode)
思考:为了满足数字所有位上单调递增,需要先依据给出的数字n进行逐位判断,从倒数第二位开始,若是此位置数字大于后面一位的数字,则此位置数字-1,直到不大于后面一位数字为止。
通过此操作使得数字满足单调递增,接下来需要让这个数字最大,即从前面处理过的最后一个位置(其左边一位数字是最后一个-1操作的)开始,由前向后,把所有数字都改为9,这样使得数字最大。
代码:
class Solution:
def monotoneIncreasingDigits(self, n: int) -> int:
num = str(n)
s = len(num)
for i in range(s-1, 0, -1):
if num[i-1] > num[i]: # 前一位大于后一位数字
# 减小前一位
num = num[:i-1] + str(int(num[i-1])-1) + num[i:]
s = i
for i in range(s, len(num)):
num = num[:i] + '9' + num[i+1:]
return int(num)
题目链接:968. 监控二叉树 - 力扣(LeetCode)
思考:拿到题目的直观感觉是,二叉树的顶层和最底层都不放摄像头,在中间层放摄像头效果会最好。但是中间层比较复杂,涉及到放置摄像头的位置左右节点的情况分析,题目分析起来难度较大。
使用三种状态标记每个节点的覆盖情况:
0:该节点未被覆盖(需要被监控)
1:该节点安装了摄像头(可以监控自身、父节点和子节点)
2:该节点被覆盖(但没有安装摄像头)
对于空节点,返回状态 2
(视为已覆盖,不影响父节点决策)。
递归左右子树,需要按照以下情况分析:
情况1:左右子节点都已覆盖(状态 2
),当前节点无需安装摄像头,返回 0
(未覆盖)。
情况2:左右子节点至少有一个未覆盖(状态 0
),当前节点必须安装摄像头(状态 1
),并增加摄像头计数。
情况3:左右子节点至少有一个安装了摄像头(状态 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:
# 从下往上安装摄像头:跳过leaves这样安装数量最少,局部最优 -> 全局最优
# 先给leaves的父节点安装,然后每隔两层节点安装一个摄像头,直到Head
# 0: 该节点未覆盖
# 1: 该节点有摄像头
# 2: 该节点有覆盖
# 定义递归函数
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 左节点覆盖,右节点无覆盖
elif left == 0 or right == 0:
result[0] += 1
return 1
# 情况3:
# left == 1 && right == 2 左节点有摄像头,右节点有覆盖
# left == 2 && right == 1 左节点有覆盖,右节点有摄像头
# left == 1 && right == 1 左右节点都有摄像头
else:
return 2