56. 合并区间
以数组 intervals
表示若干个区间的集合,其中单个区间为 intervals[i] = [starti, endi]
。请你合并所有重叠的区间,并返回 一个不重叠的区间数组,该数组需恰好覆盖输入中的所有区间 。
示例 1:
输入:intervals = [[1,3],[2,6],[8,10],[15,18]] 输出:[[1,6],[8,10],[15,18]] 解释:区间 [1,3] 和 [2,6] 重叠, 将它们合并为 [1,6].
示例 2:
输入:intervals = [[1,4],[4,5]] 输出:[[1,5]] 解释:区间 [1,4] 和 [4,5] 可被视为重叠区间。
提示:
1 <= intervals.length <= 104
intervals[i].length == 2
0 <= starti <= endi <= 104
思路:本题与LeedCode452.用最少数量的箭引爆气球和 435. 无重叠区间很像,都是区间覆盖的问题,需要先将区间按照左边界从小到大排序,intervals[i][0] <= intervals[i - 1][1],即intervals[i]的左边界 <= intervals[i - 1]的右边界,则一定有重叠。(本题相邻区间也算重贴,所以是<=)
class Solution {public int[][] merge(int[][] intervals) {List<int[]> result =new LinkedList<>();Arrays.sort(intervals,(o1,o2)->o1[0]-o2[0]);int start=intervals[0][0];int end=intervals[0][1];for(int i=1;i<intervals.length;i++){if(intervals[i][0]<=end){end=Math.max(end,intervals[i][1]);//重合就更新当前区间}else{result.add(new int[]{start,end});//如果新区间不重合,加入上一个区间start=intervals[i][0];end=intervals[i][1];}}result.add(new int[]{start,end});//将最后一次结果加入return result.toArray(new int[result.size()][]);}
}
738. 单调递增的数字
当且仅当每个相邻位数上的数字 x
和 y
满足 x <= y
时,我们称这个整数是单调递增的。
给定一个整数 n
,返回 小于或等于 n
的最大数字,且数字呈 单调递增 。
示例 1:
输入: n = 10 输出: 9
示例 2:
输入: n = 1234 输出: 1234
示例 3:
输入: n = 332 输出: 299
提示:
0 <= n <= 109
思路:
假设这个数是98,n[i]>n[i+1],让n[i]--,n[i+1]=9,即98的单调递增数就是89
如果从前往后遍历,n[i+1]不仅受n[i]影响,还受n[i+2]影响,例如332->329 这时 3又比2大了
如果从后往前遍历,332->329->299,重复利用了上一次的结果总体来说,从后往前遍历,遇见n[i]<n[i+1]的情况,让n[i]-1,让i+1与之后的位置都变为9
class Solution {public int monotoneIncreasingDigits(int n) {String temp=String.valueOf(n);char[] chars=temp.toCharArray();int index = chars.length;//记录开始填9的位置for(int i=chars.length-2;i>=0;i--){if(chars[i]>chars[i+1]){index=i+1;chars[i]--;}}for(int i=index;i<chars.length;i++){chars[i]='9';}return Integer.parseInt(String.valueOf(chars));}
}
968. 监控二叉树
给定一个二叉树,我们在树的节点上安装摄像头。
节点上的每个摄影头都可以监视其父对象、自身及其直接子对象。
计算监控树的所有节点所需的最小摄像头数量。
示例 1:
输入:[0,0,null,0,0] 输出:1 解释:如图所示,一台摄像头足以监控所有节点。
示例 2:
输入:[0,0,null,0,null,0,null,null,0] 输出:2 解释:需要至少两个摄像头来监视树的所有节点。 上图显示了摄像头放置的有效位置之一。
提示:
- 给定树的节点数的范围是
[1, 1000]
。 - 每个节点的值都是 0。
思路:
把摄像头优先放在叶节点的父节点上
所以我们要从下往上看,局部最优:让叶子节点的父节点安摄像头,所用摄像头最少,整体最优:全部摄像头数量所用最少!
在二叉树中如何从低向上推导呢?
可以使用后序遍历也就是左右中的顺序,这样就可以在回溯的过程中从下到上进行推导了。
如何隔两个节点放一个摄像头?
我们分别有三个数字来表示:
0:该节点无覆盖
1:本节点有摄像头
2:本节点有覆盖
遇见空结点怎么办?
空节点的状态只能是有覆盖,这样就可以在叶子节点的父节点放摄像头了
单层递归逻辑:
情况1:左右节点都有覆盖
左孩子有覆盖,右孩子有覆盖,那么此时中间节点应该就是无覆盖的状态了。
情况2:左右节点至少有一个无覆盖的情况
如果是以下情况,则中间节点(父节点)应该放摄像头:
left == 0 && right == 0 左右节点无覆盖
left == 1 && right == 0 左节点有摄像头,右节点无覆盖
left == 0 && right == 1 左节点有无覆盖,右节点摄像头
left == 0 && right == 2 左节点无覆盖,右节点覆盖
left == 2 && right == 0 左节点覆盖,右节点无覆盖
这个不难理解,毕竟有一个孩子没有覆盖,父节点就应该放摄像头。
此时摄像头的数量要加一,并且return 1,代表中间节点放摄像头。
情况3:左右节点至少有一个有摄像头
如果是以下情况,其实就是 左右孩子节点有一个有摄像头了,那么其父节点就应该是2(覆盖的状态)
left == 1 && right == 2 左节点有摄像头,右节点有覆盖
left == 2 && right == 1 左节点有覆盖,右节点有摄像头
left == 1 && right == 1 左右节点都有摄像头
情况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(travel(root)==0)//根节点没父亲结点,如果根节点没覆盖到,则给根节点加一个摄像头res++;return res;}public int travel(TreeNode cur){//空结点表示有覆盖if(cur==null) return 2;int left=travel(cur.left);int right=travel(cur.right);if(left==2&&right==2) return 0;//左右都覆盖,当前结点不覆盖else if(left==0||right==0) {res++;return 1;}//左右又一个没覆盖,则该节点放置摄像头else return 2;//左右孩子有一个有摄像头,则当前结点为覆盖状态}
}