代码随想录 (programmercarl.com)
738.单调递增的数字
一、暴力解法
从大大小遍历各个位,找到最先满足条件的单调递增数字
力扣上超时了
二、贪心思路
给定数字从后往前遍历,发现大于的情况,就将前一位-1,当前改为9
以下是错误❌代码:
class Solution {
public int monotoneIncreasingDigits(int n) {
String s = String.valueOf(n);
char[] chars = s.toCharArray();
for (int i = chars.length - 1; i >= 1; i--){
if (chars[i - 1] > chars[i]){
chars[i - 1]--;
chars[i] = '9' ;
//字符9才是9,如果直接写9,就是'\t'
}
}
return Integer.parseInt(String.valueOf(chars));
}
}
❌错误原因:100的时候输出的结果是90,因为0和0不满足大于关系,不会改变为9。
但其实,这里一旦前面有大于关系,后面所有位数都要改为9才可以,这时,就需要定义一个start,来记录从start开始直到末尾,所有都赋值为9。
正确✔代码:
class Solution {
public int monotoneIncreasingDigits(int n) {
String s = String.valueOf(n);
char[] chars = s.toCharArray();
int start = chars.length;
for (int i = chars.length - 1; i >= 1; i--){
if (chars[i] < chars[i - 1]){
chars[i - 1]--;
start = i;
}
}
for (int i = start; i < chars.length; i++) {
chars[i] = '9';
}
return Integer.parseInt(String.valueOf(chars));
}
}
968.监控二叉树
卡尔:“本题是贪心和二叉树的一个结合,比较难,一刷大家就跳过吧。”
====所以暂时跳过了====
2024.1.18更新
大体思路就是从低到上(后序遍历),先给叶子节点父节点放个摄像头,然后隔两个节点放一个摄像头,直至到二叉树头结点。
分别有三个数字来表示每个节点的状态:
- 0:该节点无覆盖
- 1:本节点有摄像头
- 2:本节点有覆盖
设计初衷:尽量让叶子节点的父节点放置摄像头
所以空节点的状态只能是有覆盖,这样就可以在叶子节点的父节点放摄像头
递归的终止条件是遇到了空节点,此时应该返回2(有覆盖)
主要有如下四类情况:
- 情况1:左右节点都有覆盖(2),此时中间节点应该就是无覆盖(0)的状态了;
- 情况2:左右节点至少有一个无覆盖(0)的情况,则中间节点(父节点)应该放摄像头(1);
- 情况3:左右节点至少有一个有摄像头(1),那么其父节点就应该是覆盖的状态(2);
- 情况4:头(根)结点没有覆盖,摄像头结果++。
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
int res = 0;
public int minCameraCover(TreeNode root) {
if(traversal(root) == 0){//情况4:头(根)结点没有覆盖,摄像头结果++。
res++;
}
return res;
}
public int traversal(TreeNode root) {
if (root == null){
return 2;
}
int left = traversal(root.left);
int right = traversal(root.right);
if (left == 2 && right == 2){//情况1:左右节点都有覆盖(2),此时中间节点应该就是无覆盖(0)的状态了;
return 0;
}
if (left == 0 || right == 0){//情况2:左右节点至少有一个无覆盖(0)的情况,则中间节点(父节点)应该放摄像头(1)
res++;
return 1;
}
if (left == 1 || right == 1){//情况3:左右节点至少有一个有摄像头(1),那么其父节点就应该是覆盖的状态(2);
return 2;
}
return -1;//不会走到这里,前面都已经包含了所有情况,这里随便返回一个值就可以
}
}
总结
局部最优==》全局最优。
贪心无套路,忽难忽易。