代码随想录算法训练营第 30 天 | 56. 合并区间、738. 单调递增的数字、968. 监控二叉树

56. 合并区间

题目链接

妙:
更新右边界时,不用 i - 1,而是用 result 数组的最后一个元素的右边界。这样直接就更新了,不用删除再插入。

class Solution {
    public int[][] merge(int[][] intervals) {
        int n = intervals.length;
        Arrays.sort(intervals, Comparator.comparingInt(a -> a[0]));
        List<int[]> result = new ArrayList<>();
        result.add(intervals[0]);

        for (int i = 1; i < n; i++) {
            if (intervals[i][0] <= result.getLast()[1]) {
                // 更新右边界,不用更新左边界(左边界仍为上一个的左边界,因为已按左边界排序)
                result.getLast()[1] = Math.max(result.getLast()[1], intervals[i][1]);
            } else {
                result.add(intervals[i]);
            }
        }

        return result.toArray(new int[0][]);
    }
}

738. 单调递增的数字

题目链接

思路
从后向前遍历,遇到前一位大于后一位,前一位减 1,后一位及之后全部赋成 9.

设置一个 flag,表示从这一位开始后面的元素全部赋成 9(防止 1000 -> 0900 的情况,应该是 1000 -> 999)

class Solution {
    public int monotoneIncreasingDigits(int n) {
        String str = String.valueOf(n);
        char[] arr = str.toCharArray();
        int len = str.length();
        int flag = len; // flag 初值赋为 len,以应对给的数本来就是单调递增的情况

        for (int i = len - 1; i > 0; i--) {
            if (arr[i - 1] > arr[i]) {
                arr[i - 1] -= 1;
                flag = i;
            }
        }
        
        for (int i = flag; i < len; i++) {
            arr[i] = '9';
        }

        return Integer.parseInt(String.valueOf(arr));
    }
}

968. 监控二叉树

题目链接

后序(左右中)

每个节点,只有 3 种状态:

0 -> 无覆盖(未被摄像头覆盖)
1 -> 有摄像头
2 -> 有覆盖(被摄像头覆盖)

对 null 节点,应该设置为有覆盖状态。(用反证法证明)

思路:
优先从叶子节点往上遍历,在叶子节点的父节点放摄像头。

左右孩子四种情况:

  1. 左右孩子都是有覆盖 -> 父节点是无覆盖(不需要放摄像头)
  2. 左右孩子至少有 1 个无覆盖,另一个孩子状态不管 -> 父节点应该放摄像头
  3. 左右孩子至少有一个有摄像头(另一个孩子不是无覆盖,即条件 2 不满足的情况) -> 父节点是有覆盖状态(不需要放摄像头)
  4. 特殊情况:如果遍历完了,根节点还是无覆盖的情况,则根节点要放一个摄像头

在这里插入图片描述

其实一共有 6 种常规情况(2C3 + 3 = 6),上面第一种情况包含 1 种,第二种情况包含 3 种,第三种情况包含 2 种。已经全部覆盖到了。

class Solution {
    int result = 0;
    public int minCameraCover(TreeNode root) {
        result = 0; // 养成好习惯,main 函数使用全局变量用前先初始化
        if (traversal(root) == 0) { // 如果遍历完后根节点无覆盖,根节点额外放一个摄像头,对应情况 4
            result++;
        }
        return result;
    }

    public int traversal(TreeNode root) {
        // 0 -> 无覆盖(未被摄像头覆盖)
        // 1 -> 有摄像头
        // 2 -> 有覆盖(被摄像头覆盖)
        if (root == null) {
            return 2; // null 节点被视作有覆盖
        }

        // 左
        int left = traversal(root.left);

        // 右
        int right = traversal(root.right);

        // 中
        if (left == 2 && right == 2) { // 左右孩子都有覆盖,父节点返回未覆盖
            return 0;
        }
        if (left == 0 || right == 0) { // 左右孩子任意一个未覆盖,父节点放摄像头
            result++;
            return 1;
        }
        if (left == 1 || right == 1) { // 左右孩子任意一个有摄像头,另一个不是无覆盖,父节点返回有覆盖
            return 2;
        }
        return -1; // 逻辑不会走到这里
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值