代码随想录算法训练营第31天| 56. 合并区间 738.单调递增的数字 968.监控二叉树 (可跳过)
Leetcode 56. 合并区间
题目链接:https://leetcode.cn/problems/merge-intervals/description/
题目描述:
以数组 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
思路:贪心
代码1:
class Solution {
public int[][] merge(int[][] intervals) {
List<int[]> res = new LinkedList<>();
// 按照左边界排序
Arrays.sort(intervals,(a,b)->
Integer.compare(a[0],b[0])
);
// 最小左边界
int start = intervals[0][0];
// 右边界
int right = intervals[0][1];
for(int i = 1 ; i < intervals.length ; i++){
// 当左边界大于最大右边界
if(intervals[i][0] > right){
// 加入区间
res.add(new int[]{start,right});
// 更新左边界start
start = intervals[i][0];
right = intervals[i][1];
}else{
// 更大的右边界,有重叠部分
right = Math.max(right,intervals[i][1]);
}
}
res.add(new int[]{start,right});
return res.toArray(new int[res.size()][]);
}
}
Leetcode 738.单调递增的数字
题目链接:https://leetcode.cn/problems/monotone-increasing-digits/description/
题目描述:
当且仅当每个相邻位数上的数字 x
和 y
满足 x <= y
时,我们称这个整数是单调递增的。
给定一个整数 n
,返回 小于或等于 n
的最大数字,且数字呈 单调递增 。
示例 1:
输入: n = 10
输出: 9
示例 2:
输入: n = 1234
输出: 1234
示例 3:
输入: n = 332
输出: 299
提示:
0 <= n <= 109
思路:贪心
代码1:
class Solution {
public int monotoneIncreasingDigits(int n) {
//将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));
}
}
代码2:
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));
}
}
总结:
Leetcode 968.监控二叉树 (可跳过)
题目链接:https://leetcode.cn/problems/binary-tree-cameras/description/
题目描述:
给定一个二叉树,我们在树的节点上安装摄像头。
节点上的每个摄影头都可以监视其父对象、自身及其直接子对象。
计算监控树的所有节点所需的最小摄像头数量。
示例 1:
输入:[0,0,null,0,0]
输出:1
解释:如图所示,一台摄像头足以监控所有节点。
示例 2:
输入:[0,0,null,0,null,0,null,null,0]
输出:2
解释:需要至少两个摄像头来监视树的所有节点。 上图显示了摄像头放置的有效位置之一。
提示:
- 给定树的节点数的范围是
[1, 1000]
。 - 每个节点的值都是 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 res = 0;
public int minCameraCover(TreeNode root) {
// 后序遍历
// 节点有三种状态
// 1、该节点无覆盖 0
// 2、该节点有摄像头 1
// 3、本节点被覆盖 2
// 空节点属于有覆盖状态
// 主要有四种情况
// 1、左右节点都有覆盖
// 左孩子有覆盖,右孩子有覆盖,那么此时中间节点应该就是无覆盖的状态了。
// 2、左右只有一个无覆盖
//有一个孩子没有覆盖,父节点就应该放摄像头。
// 3、左右节点至少有一个有摄像头
// 左右孩子节点有一个有摄像头了,那么其父节点就应该是2(覆盖的状态)
// 4、头结点没有覆盖
// 对根节点进行检验,防止根节点是无覆盖状态
if(minCame(root) == 0){
res++;
}
return res;
}
// 节点有三种状态
// 1、该节点无覆盖 0
// 2、该节点有摄像头 1
// 3、本节点被覆盖 2
public int minCame(TreeNode root){
if(root == null){
// 空节点默认为 有覆盖状态,避免在叶子节点上放摄像头
return 2;
}
int left = minCame(root.left);
int right = minCame(root.right);
// 如果左右节点都覆盖,那么此时中间节点应该就是无覆盖的状态了。
if(left == 2 && right == 2){
return 0;
}else if(left == 0 || right == 0){
// 左右节点都是无覆盖状态,那 根节点此时应该放一个摄像头
// (0,0) (0,1) (0,2) (1,0) (2,0)
// 状态值为 1 摄像头数 ++;
res++;
return 1;
}else{
// 左右节点的 状态为 (1,1) (1,2) (2,1) 也就是左右节点至少存在 1个摄像头,
// 那么本节点就是处于被覆盖状态
return 2;
}
}
}
(2,0)
// 状态值为 1 摄像头数 ++;
res++;
return 1;
}else{
// 左右节点的 状态为 (1,1) (1,2) (2,1) 也就是左右节点至少存在 1个摄像头,
// 那么本节点就是处于被覆盖状态
return 2;
}
}
}
######
######