贪心最后一天!
LeetCode 738 单调递增的数字
题目链接:738. 单调递增的数字 - 力扣(Leetcode)
这题很明显需要贪心地替换数字,从后往前遍历,遇到前一位数位比当前大的数位,就能将当前数位替换为9,并将前一个数位的数值减1,但自己实现时并没有想到,一旦替换了某一位为9,比它低的数位都应该替换为9,这样才能保证数尽可能大,还避免中间某一位替换为9之后又出现非递增的情况:
class Solution:
def isValid(self, s):
for i in range(1, len(s)):
if s[i] < s[i-1]:
return False
return True
def monotoneIncreasingDigits(self, n: int) -> int:
digits = list(str(n))
if self.isValid(digits):
return n
flag = len(digits) # 标记数字从第几位开始替换为9
for i in range(len(digits)-1, 0, -1):
if digits[i-1] > digits[i]:
flag = i
digits[i-1] = str(int(digits[i-1]) - 1)
for i in range(flag, len(digits)):
digits[i] = '9'
return int(''.join(digits))
LeetCode 968 监控二叉树
题目链接:968. 监控二叉树 - 力扣(Leetcode)
监控二叉树看着好像很简单,容易想到通过后续遍历,从叶节点开始判断,通过两个返回值返回已经放置的监控数量,以及判断根节点是否需要放置监控:
# 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:
if not root.left and not root.right:
return 1
def dfs(node):
if not node or (not node.left and not node.right):
return 0, False # 叶节点
num_left, left = dfs(node.left)
num_right, right = dfs(node.right)
if left or right:
# 其中一个节点有摄像头,当前节点不放
return num_left + num_right, False
else:
# 左右节点都没有,当前节点必须放一个
return num_left + num_right + 1, True
return dfs(root)[0]
提交时对于测试用例[0,0,0,null,null,null,0],两个叶节点都不放,以上代码的判断逻辑就会只放置一个监控,导致有一个叶节点不能被监控到,属于是考虑不全面的表现。讲解中将节点的状态分文有覆盖、无覆盖和有监控三种状态,逻辑更严密:
class Solution:
def __init__(self):
self.res = 0
def minCameraCover(self, root: Optional[TreeNode]) -> int:
# 0 1 2分别代表无覆盖,有监控和有覆盖的状态
def dfs(node):
if not node:
return 2 # 空节点认为是有覆盖
left = dfs(node.left)
right = dfs(node.right)
# 左右节点都有覆盖
if left == 2 and right == 2:
return 0
if left == 0 or right == 0:
self.res += 1
return 1
if left == 1 or right == 1:
return 2
if dfs(root) == 0:
self.res += 1
return self.res
贪心算法小结
贪心有点玄学(bushi,需要一些解题直觉,也需要多做题多锻炼思维。