代码随想录Day39

738.单调递增的数字

题目:738. 单调递增的数字 - 力扣(LeetCode)

思路:感觉不难,就是把数字先按照位数取出来,再进行比较,不行就递减,每次检查一下是不是单调递增,暴力算法可能会比较耗时,应该是有技巧可以某些数字不检查的,尬住了,我不知道怎么取出来数字

我想到了,找到数组中最大的数字,把这个数字之后的数字都变成9,比如说6711,7最大,我就把11都变成1,7减去1,也就是6699

尝试(部分AC但是超出时间限制)
class Solution {
    public int monotoneIncreasingDigits(int n) {
        while(isValid(n) != true){
            n--;
        }
        return n;
    }
    public boolean isValid(int n){
        //取出每个数字
        int length = 0;
        int temp = n;
        while (temp > 0) {
            length++;
            temp /= 10; // 移动到下一个数字
        }
        int[] digits = new int[length];
        for (int i = length - 1; i >= 0; i--) {
            digits[i] = n % 10; // 获取当前最低位的数字
            n /= 10; // 移动到下一个数字
        }
        //判断数字是否递增,不是则返回false
        for(int i = 1; i<length ; i++){
            if(digits[i]<digits[i-1]) return false;
        }
        //返回false
        return true;
    }
}
第二次尝试

先找到最大的数字所在的下标,把改数字减1,再把后面的数字变成9,我的思路接近答案,但是还是不行,比如【7,1,1,9】的情况

class Solution {
    public static int max = 0;
    public static int minIndex = 0;
    public int monotoneIncreasingDigits(int n) {
        int length = 0;
        int temp = n;
        while (temp > 0) {
            length++;
            temp /= 10; // 移动到下一个数字
        }
        int[] digits = new int[length];
        for (int i = length - 1; i >= 0; i--) {
            digits[i] = n % 10; // 获取当前最低位的数字
            n /= 10; // 移动到下一个数字
        }
        //找到
        for(int i = 0; i < length; i++){
            if(digits[i] > max){
                max = digits[i];
                minIndex = Math.min(minIndex,i);
            }
        }
        int result = 0;
        digits[minIndex] = digits[minIndex]  -1;
        for(int i = minIndex; i < length-1; i++){
            digits[i] = 9;
        }
        for (int digit : digits) {
            result = result * 10 + digit;
        }
        return result;

    }
}
答案
class Solution {
    public int monotoneIncreasingDigits(int n) {
        String s = String.valueOf(n);
        char[] chars = s.toCharArray();
        int start = s.length();
        for (int i = s.length() - 2; i >= 0; i--) {
            if (chars[i] > chars[i + 1]) {
                chars[i]--;
                start = i+1;
            }
        }
        for (int i = start; i < s.length(); i++) {
            chars[i] = '9';
        }
        return Integer.parseInt(String.valueOf(chars));
    }
}
小结
  • 从后向前遍历,一旦出现strNum[i - 1] > strNum[i]的情况(非单调递增),首先想让strNum[i - 1]减一,strNum[i]赋值9
  • 只需要先通过【valueOf】把数字转换为字符串,再用【toCharArray】把字符串转换为字符数组就行

968.监控二叉树

题目:968. 监控二叉树 - 力扣(LeetCode)

思路:首先我不知道怎么判断一个节点能当作监控节点,监控节点的作用就是能够连接到周围一步范围的节点,我需要找到能够到达所有节点的最少所需监控节点,目前的一个思路就是,采用层序遍历,记录所有节点能够到达的节点数量,我只知道这个思路,得到这个数组之后,要怎么挑出监控节点就不会了

尝试(部分AC)
class Solution {
    public int minCameraCover(TreeNode root) {
        int result =0;
        int nodeNum = 0;
        List<List<Integer>> resList = new ArrayList<List<Integer>>();
        Queue<TreeNode> que = new LinkedList<TreeNode>();
        que.offer(root);

        while(!que.isEmpty()){
            List<Integer> itemList = new ArrayList<Integer>();
            int len = que.size();
            while(len>0){
                // 记录节点个数
                nodeNum += len;
                TreeNode temp = que.poll();
                int count =0;
                if(temp.left != null){
                    que.offer(temp.left);
                    count++;
                };
                if(temp.right != null){
                    que.offer(temp.right);
                    count++;
                };
                itemList.add(count);
                len--;
            }
            resList.add(itemList);
        }
        // 遍历itemlist,把元素从大到小加起来,一旦加起来之后等于节点个数,就返回当前收集到的元素个数
        return result;
        
    }
}
答案
class Solution {
    static int ans;
    public int minCameraCover(TreeNode root) {
        ans = 0; // 初始化
        if(f(root) == 0) ans ++;
        return ans;
    }
    // 定义 f 函数有三种返回值情况
    // 0:表示 x 节点没有被相机监控,只能依靠父节点放相机
    // 1:表示 x 节点被相机监控,但相机不是放在自身节点上
    // 2:表示 x 节点被相机监控,但相机放在自身节点上
    public static int f(TreeNode x) {
        if(x == null) return 1; // 空树认为被监控,但没有相机
        // 左右递归到最深处
        int l = f(x.left);
        int r = f(x.right);
        // 有任意一个子节点为空,就需要当前节点放相机,不然以后没机会
        if(l == 0 || r == 0) {
            ans ++; // 放相机
            return 2;
        }
        // 贪心策略,左右子树都被监控,且没有监控到当前节点,
        // 那么最有利的情况就是将相机放置在当前节点父节点上,
        // 因为这样能多监控可能的子树节点和父父节点
        if(l == 1 && r == 1) return 0;
        // 剩下情况就是左右子树有可能为 2,即当前节点被监控
        return 1; 
    }
}
小结
  • 首先,要从下往上遍历,也就是后序遍历
  • 其次,要搞清楚节点有几种状态,根据子节点的状态来判断摄像头的数量是否需要增加
  • 三种状态,被监控(带相机),被监控(无相机),无监控
  • 左右孩子存在一个是无监控,当前节点就要加上监控,返回状态【被监控(带相机)】;左右节点都被监控,当前节点就不加监控,返回状态【无监控】;其它情况下,返回状态【被监控(无相机)】

  • 5
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值