代码随想录算法训练营第三十七天 | 738.单调递增的数字、968.监控二叉树、总结
738.单调递增的数字
贪心算法
思路:本题暴力做法是从当前数字开始从大到小遍历,符合题意则返回结果,时间复杂度为O(m*n),m 为 n 的数字长度。
对于贪心算法,首先要明确遍历方向。本题使用从后向前遍历。如果从前向后遍历的话,遇到strNum[i - 1] > strNum[i] 的情况,让 strNum[i - 1] 减一,但此时如果 strNum[i - 1] 减一了,可能又小于 strNum[i - 2]。而从后向前遍历,就可以重复利用上次比较得出的结果了,从后向前遍历332的数值变化为:332 -> 329 -> 299
class Solution {
public int monotoneIncreasingDigits(int n) {
String s = String.valueOf(n);
char[] chars = s.toCharArray();
int flag = s.length();
for(int i = s.length() - 1; i > 0; i--) {
if(chars[i - 1] > chars[i]) {
chars[i - 1]--;
flag = i;
}
}
for(int i = flag; i < chars.length; i++) {
chars[i] = '9';
}
return Integer.parseInt(String.valueOf(chars));
}
}
968.监控二叉树
贪心算法
思路:本题线索在于摄像头不会放在叶子节点上,所以要从下往上看。
- 局部最优:让叶子节点的父节点安摄像头,所用摄像头最少;
- 整体最优:全部摄像头数量所用最少;
确定贪心策略后,还有两个问题——遍历顺序以及如何隔两个节点放一个摄像头。
- 遍历顺序:使用后序遍历,这样就可以在回溯的过程中从下到上进行推导了。
- 如何隔两个节点放一个摄像头:首先明确每个节点可能的几种状态——①该节点无覆盖;②本节点有摄像头;③本节点有覆盖。
两个注意点:
- 为何没有本节点无摄像头的情况?其实无摄像头就是无覆盖或者有覆盖的状态;
- 空节点的状态只能是有覆盖,这样就可以在叶子节点的父节点放摄像头了
class Solution {
int res=0;
public int minCameraCover(TreeNode root) {
// 对根节点的状态做检验,防止根节点是无覆盖状态 .
if(minCame(root)==0){
res++;
}
return res;
}
/**
节点的状态值:
0 表示无覆盖
1 表示 有摄像头
2 表示有覆盖
后序遍历,根据左右节点的情况,来判读 自己的状态
*/
public int minCame(TreeNode root){
if(root==null){
// 空节点默认为 有覆盖状态,避免在叶子节点上放摄像头
return 2;
}
int left=minCame(root.left);
int right=minCame(root.right);
// 如果左右节点都覆盖了的话, 那么本节点的状态就应该是无覆盖,没有摄像头
if(left==2&&right==2){
//(2,2)
return 0;
}else if(left==0||right==0){
// 左右节点都是无覆盖状态,那 根节点此时应该放一个摄像头
// (0,0) (0,1) (0,2) (1,0) (2,0)
// 状态值为 1 摄像头数 ++;
res++;
return 1;
}else{
// 左右节点的 状态为 (1,1) (1,2) (2,1) 也就是左右节点至少存在 1个摄像头,
// 那么本节点就是处于被覆盖状态
return 2;
}
}
}
贪心算法总结
贪心算法的总结:代码随想录—贪心算法总结篇