贪心算法part05
day36-1 ●56. 合并区间
题意
解题思路
不要在原数组进行操作,在原数组上操作会非常复杂,不仅合并两个数组数组后要插入新的数组而且还有删除原来的两个数组
代码实现
class Solution {
/**
*时间复杂度: O(nlogn)
*空间复杂度: O(logn),排序需要的空间开销
*/
public int[][] merge(int[][] intervals) {
List<int[]> result = new ArrayList<>();
// 除掉特殊情况
if (intervals.length == 0) {
return result.toArray(new int[][]{});
}
// 根据左区间进行排序
Arrays.sort(intervals, (a, b) -> Integer.compare(a[0], b[0]));
result.add(intervals[0]);
for (int i = 1; i < intervals.length; i++) {
// 合并区间
if (result.get(result.size() - 1)[1] >= intervals[i][0]) {
// 取最大的右区间
result.get(result.size() - 1)[1] = Math.max(result.get(result.size() - 1)[1], intervals[i][1]);
// 添加元素
}else {
result.add(intervals[i]);
}
}
return result.toArray(new int[][]{});
}
}
总结
重叠类问题:排序—>重叠(1.重叠怎么处理 2.没有重叠怎么处理)
day36-2 ● 738.单调递增的数字
题意
关键点:
大于等于
单调递增
理解思路
遍历顺序从后往前
flag的秒用
模拟过程
代码实现
class Solution {
public int monotoneIncreasingDigits(int n) {
String s = String.valueOf(n);
char[] chars = s.toCharArray();
// flag 有秒用,如果是1234的情况,就不会走下面的两段for循环的逻辑
int flag = s.length();
for (int i = s.length() - 1; i > 0; i--) {
if (chars[i - 1] > chars[i]) {
chars[i - 1]--;
flag = i;
}
}
for (int i = flag; i < s.length(); i++) {
chars[i] = '9';
}
//return Integer.parseInt(String.valueOf(chars));
return Integer.parseInt(new String(chars));
}
}
总结
遍历顺序:只有从后向前遍历才能重复利用上一次比较的结果
day36-3 ● 968.监控二叉树 (可跳过)
题意
每天摄像头可以监视其父对象、自身、及其直接子对象
使用最少的摄像头数量
叶子节点不要放摄像头,要重复利用摄像头的监控范围
解题思路
优先从叶子节点的父节点开始去安装摄像头,然后每隔两个节点按照一个摄像头
节点状态
0: 无覆盖
1: 有摄像头
2: 有覆盖
无摄像头的状态已近被0(无覆盖)和2(有覆盖)的状态覆盖掉了
null节点应该是有覆盖状态才不违背贪心的初衷
三种情况:
特殊情况(根节点没有摄像头)没有考虑:
代码实现
/**
* 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(traveral(root) == 0){
result++;
}
return result;
}
/**
* 节点状态:
* 0: 无覆盖
* 1: 有摄像头
* 2: 有覆盖
*/
public int traveral(TreeNode cur){
// 保证叶子节点为无覆盖
if(cur == null){
return 2;
}
// 左
int left = traveral(cur.left);
// 右
int right = traveral(cur.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;
}
}
总结
- 优先从叶子节点的父节点开始去安装摄像头,然后每隔两个节点按照一个摄像头