代码随想录算法训练营第三十七天|738.单调递增的数字、968.监控二叉树、总结

代码随想录 (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;//不会走到这里,前面都已经包含了所有情况,这里随便返回一个值就可以
    }
}

总结 

局部最优==》全局最优。

贪心无套路,忽难忽易。

  • 9
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Buuuleven.(程序媛

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值