代码随想录算法训练营第三十七天| LeetCode56. 合并区间、LeetCode738.单调递增的数字、LeetCode968. 监控二叉树

#LeetCode 56. Merge Intervals

#LeetCode 56. 视频讲解:贪心算法,合并区间有细节!LeetCode:56.合并区间_哔哩哔哩_bilibili

依然是通过比较左边界来判断的是否重叠,如果第i 个数组的左边界小于第i - 1 个数组的右边界,则代表存在重叠的区间,但不会直接加入,因为可能有一种情况是:[1, 5] 和 [2, 3],所以记录下最新的右边界,继续比较。如果是不重叠区间,则直接存入list 数组。在存入的时候采用的方式是:list.add(new int[] {start, right}); 这样的形式通常被用做存储intervals 或者ranges。

在一些情况下,为了确保最后的边缘情况,会显式的再次添加当前的区间来防止边缘情况的发生。

代码:

class Solution {
    public int[][] merge(int[][] intervals) {
        List<int[]> list = new LinkedList<>();
        Arrays.sort(intervals, (a, b) -> {
            return Integer.compare(a[0], b[0]);
        });
        int start = intervals[0][0]; // left
        int right = intervals[0][1];
        for (int i = 1; i < intervals.length; i++) {
            if (intervals[i][0] <= right) {
                right = Math.max(right, intervals[i][1]);
            } else {
                list.add(new int[] {start, right});
                start = intervals[i][0];
                right = intervals[i][1];
            }
        }
        list.add(new int[] {start, right});
        return list.toArray(new int[list.size()][]);
    }
}

#LeetCode 738. Monotone Increasing Digits

#LeetCode 738. 视频讲解:贪心算法,思路不难想,但代码不好写!LeetCode:738.单调自增的数字_哔哩哔哩_bilibili

首先把整数改为字符串的原因是方便逐位操作每一位数字,再将字符串转换为字符数组后,可以通过下标操作字符数组中的每一个字符,这样可以方便地修改每一位数字。最后,将修改后的字符数组重新转换为字符串,再将字符串转换为整数,得到最终结果。

设置一个flag 参数的作用是,记录在哪一位之后都变为9,如果不记录,在数字是1000 时,会因为后两位相同而不做任何操作,最后得到的数字是900而不是999。flag 的起始设置是指向数字的最后一位,是为了在没有需要更新操作的时候,可以不进行赋值为9 的操作。

整个的遍历顺序是从后向前操作,如果从前向后操作,对于数字332,那么会改为329,那么就不符合题目对于单调递增数列的要求了。

代码:

class Solution {
    public int monotoneIncreasingDigits(int n) {
        String s = String.valueOf(n);
        char[] c = s.toCharArray();
        int flag = c.length;
        for (int i = c.length - 1; i > 0; i--) {
            if (c[i] < c[i-1]) {
                c[i-1]--;
                flag = i;
            }
        }
        for (int i = flag; i < c.length; i++) {
            c[i] = '9';
        }
        return Integer.parseInt(String.valueOf(c));
    }
}

#LeetCode 968. Binary Tree Cameras

#LeetCode 968. 视频讲解:贪心算法,二叉树与贪心的结合,有点难...... LeetCode:968.监督二叉树_哔哩哔哩_bilibili

遍历的顺序是后序遍历(左右中),因为要摄像的数目最少,从叶子节点考虑,进可能少的设置摄像。叶子节点的父节点是要放置摄像的,这样再相隔2 个节点再设置一个摄像。

每个节点的状态共有三种:

状态0: 无覆盖

状态1: 有摄像

状态2: 有覆盖

在这里考虑是否存在一个状态是:无摄像状态?其实无摄像状态就是0 或者2 的情况,所以不需要单独考虑。那么对于null 的节点,状态应该为2 ,这样可以叶子节点的父节点满足最少设置的要求。

需要考虑的情况共有4 种:

情况1: 左右节点都是有覆盖的情况,那么这个节点则设置为状态0,是无覆盖。

情况2: 左右节点中至少有一个无覆盖的情况,那这个节点需要设置为状态1,将会放置一个摄像。

情况3: 左右节点至少有一个摄像,那么这个节点属于状态2,因为左右孩子节点如果有摄像,其父节点也会被覆盖到。如果是一个节点有摄像,一个节点是无覆盖,那么则属于情况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 result = 0;
    public int minCameraCover(TreeNode root) {
        if (traversal(root) == 0) {
            result ++; // case 4
        }
        return result;
    }
    public int traversal(TreeNode cur) {
        if (cur == null) {
            return 2;
        }
        int left = traversal(cur.left);
        int right = traversal(cur.right);
        if (left == 2 && right == 2) {
            return 0; // case 1
        } else if (left == 0 || right == 0) {
            result ++;
            return 1; // case 2
        } else {
            return 2; // case 3
        }
    }
    
}
  • 11
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值