代码随想录打卡|Day27(合并区间、单调递增的数字、监控二叉树)
贪心算法 Part05
合并区间
力扣题目链接
代码随想录链接
视频讲解链接
题目描述: 以数组 intervals 表示若干个区间的集合,其中单个区间为 intervals[i] = [starti, endi] 。请你合并所有重叠的区间,并返回 一个不重叠的区间数组,该数组需恰好覆盖输入中的所有区间 。
思路:对于这道题目,我们只需要按照每个区间的左边界进行从小到大排序,随后依次遍历每个区间,获取他们的范围,将范围有重叠的区间合并(取重叠区间的最小做区间和最大右区间的值),并将合并后得出的每个区间的范围重新记录,最后输出即可。
代码如下:
class Solution {public int[][] merge(int[][] intervals) {// Arrays.sort(intervals,(a,b) -> a[0] - b[0]);Arrays.sort(intervals,(a,b) -> Integer.compare(a[0],b[0]));int start = intervals[0][0] ;int end = intervals[0][1];List<int[]> res = new LinkedList<>();for(int i = 1 ; i < intervals.length ; i++){if(intervals[i][0] <= end){start = Math.min(start , intervals[i][0]);end = Math.max(end , intervals[i][1]);}else{res.add(new int[]{start , end});start = intervals[i][0];end = intervals[i][1];}}res.add(new int[]{start , end});return res.toArray(new int[res.size()][]);}
}
代码随想录代码:
/**
时间复杂度 : O(NlogN) 排序需要O(NlogN)
空间复杂度 : O(logN) java 的内置排序是快速排序 需要 O(logN)空间*/
class Solution {public int[][] merge(int[][] intervals) {List<int[]> res = new LinkedList<>();//按照左边界排序Arrays.sort(intervals, (x, y) -> Integer.compare(x[0], y[0]));//initial start 是最小左边界int start = intervals[0][0];int rightmostRightBound = intervals[0][1];for (int i = 1; i < intervals.length; i++) {//如果左边界大于最大右边界if (intervals[i][0] > rightmostRightBound) {//加入区间 并且更新startres.add(new int[]{start, rightmostRightBound});start = intervals[i][0];rightmostRightBound = intervals[i][1];} else {//更新最大右边界rightmostRightBound = Math.max(rightmostRightBound, intervals[i][1]);}}res.add(new int[]{start, rightmostRightBound});return res.toArray(new int[res.size()][]);}
}
单调递增的数字
力扣题目链接
代码随想录链接
视频讲解链接
题目描述:当且仅当每个相邻位数上的数字 x 和 y 满足 x <= y 时,我们称这个整数是单调递增的。
给定一个整数 n ,返回 小于或等于 n 的最大数字,且数字呈 单调递增 。
思路:将数组转换成为字符串再转换为数组,从尾到头判断两个相邻数字的大小是否满足递增,若不满足,前一个数字减一,后一个数字变成9.
代码如下:
class Solution {public int monotoneIncreasingDigits(int n) {String str = String.valueOf(n);char[] strArray = str.toCharArray();// 记录需要变成9的数字开始下标int index = strArray.length;for(int i = strArray.length - 2; i >= 0 ; i--){if(strArray[i] > strArray[i + 1]){strArray[i] --;index = i + 1;}}for(int i = index ; i < strArray.length ; i++)strArray[i] = '9';return Integer.parseInt(String.valueOf(strArray));}
}
另一种方法(创建了String数组,多次使用Integer.parseInt了方法,这导致不管是耗时还是空间占用都非常高,用时12ms)
class Solution {public int monotoneIncreasingDigits(int N) {String[] strings = (N + "").split("");int start = strings.length;for (int i = strings.length - 1; i > 0; i--) {if (Integer.parseInt(strings[i]) < Integer.parseInt(strings[i - 1])) {strings[i - 1] = (Integer.parseInt(strings[i - 1]) - 1) + "";start = i;}}for (int i = start; i < strings.length; i++) {strings[i] = "9";}return Integer.parseInt(String.join("",strings));}
}
监控二叉树
力扣题目链接
代码随想录链接
视频讲解链接
题目描述:给定一个二叉树,我们在树的节点上安装摄像头。
节点上的每个摄影头都可以监视其父对象、自身及其直接子对象。
计算监控树的所有节点所需的最小摄像头数量。
思路:对于二叉树的题目,使用递归解决问题的时候需要考虑是应该使用前中后哪一种顺序。在本题目之中,我们需要使用最少数量的摄像头覆盖二叉树的所有节点,那么我们就一定不能在叶子节点部署摄像头,所以我们需要隔层安放摄像头。
基于此,我们对每个节点定义三种状态:
0:该节点没有被摄像头覆盖
1:该节点安放摄像头
2:该节点被摄像头覆盖
所以,对于一个非叶子节点,他的状态会存在三种:
1.该节点的两个叶子节点被覆盖,该节点就应该先赋值为0;
2.该节点的左节点或者右节点为0,则说明该节点必须安装摄像头。
3.该节点的至少一个叶子节点安装摄像头,则该节点应该被标记为2(被覆盖)。
此外,递归结束之后,root节点的值可能还会出现为0的情况,需要单独处理,若递归函数返回值为0,则摄像头的数量应该+1;
代码如下:
/*** 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(root.left == null && root.right == null) return 1;// 还会存在root节点为0的情况,因此,需要再次判断if(minCameraCounter(root)==0) result++;return result;}/**节点的状态值:0 表示无覆盖1 表示 有摄像头2 表示有覆盖后序遍历,根据左右节点的情况,来判读 自己的状态*/// 1.确定递归函数的返回类型和传入参数类型private int minCameraCounter(TreeNode node){// 确定递归函数的结束条件// 1.当节点为叶子节点的时候,我们应该将他的值赋值为2if(node == null) return 2;// leftint left = minCameraCounter(node.left);// rightint right = minCameraCounter(node.right);// 情况1:当节点的左右孩子的值均为2,则证明节点不用部署摄像头if(left == 2 && right == 2){ return 0;}// 情况2:当节点的左孩子或右孩子的值为0的时候,就代表该节点应该部署摄像头if(left == 0 || right == 0){result++;return 1;}// 情况3:当节点的左右孩子至少存在一个摄像头的时候,那么该节点的就应该是被覆盖了else{return 2;}}
}