14.合并区间
以数组
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].
思路:
先将根据左边界从小到大将区间进行排序
然后直接把第一个区间插入result
这样result存的区间的左边界永远是最小的
只需根据是否重叠来更新右边界即可
cpp
class Solution {
static bool cmp(const vector<int>&a,const vector<int>&b)
{
return a[0]<b[0];
}
public:
vector<vector<int>> merge(vector<vector<int>>& intervals) {
vector<vector<int>>result;
if(intervals.size()==0)return result;
sort(intervals.begin(),intervals.end(),cmp);//根据左边界从小到大排序
result.push_back(intervals[0]);//把第一个区间放进去,左边界一定是最小的
for(int i=1;i<intervals.size();i++)
{
if(result.back()[1]>=intervals[i][0])//前一个区间的右边界大于后一个区间的左边界,说明重叠
{
result.back()[1]=max(result.back()[1],intervals[i][1]);//只需更新右边界
}
else
{
result.push_back(intervals[i]);//不重叠就直接放进去
}
}
return result;
}
};
-
时间复杂度: O(nlogn)快排
-
空间复杂度: O(logn),排序需要的空间开销
15.单调递增的数字
当且仅当每个相邻位数上的数字
x
和y
满足x <= y
时,我们称这个整数是单调递增的。给定一个整数
n
,返回 小于或等于n
的最大字,且数字呈 单调递增 。示例 2:
输入: n = 1234 输出: 1234
示例 3:
输入: n = 332 输出: 299
贪心思路:
从后往前遍历,如果前一位数大于后一位就把前一位数一直减,直到前一位小于等于后一位,然后把后一位设置为9
例如:332--->(3<2,3--)--->322(2-->9)--->329(3>2-->3--)--->229(2-->9)--->299
cpp
class Solution {
public:
int monotoneIncreasingDigits(int n) {
string strNUm = to_string(n);
int flag = strNUm.size();//用来记录从哪里开始变9
for(int i=strNUm.size()-1;i>0;i--)
{
if(strNUm[i-1]>strNUm[i])
{
flag=i;//记录要变成9的位置
strNUm[i-1]--;
}
}
for(int i=flag;i<strNUm.size();i++)//flag记录的是最先开始变成9的位置
{
strNUm[i]='9';
}
return stoi(strNUm);//变数字
}
};
时间复杂度:O(n),n 为数字长度
空间复杂度:O(n),需要一个字符串
16.监控二叉树
给定一个二叉树,我们在树的节点上安装摄像头。
节点上的每个摄影头都可以监视其父对象、自身及其直接子对象。
计算监控树的所有节点所需的最小摄像头数量。
(困难)
贪心思路:
叶子节点不放摄像头,因为没有子节点给叶子节点监控。监控放父节点
难点 :节点上的每个摄影头都可以监视其父对象、自身及其直接子对象,如何跳过两个节点放摄像头
假设0:无覆盖,1:有摄像头,2:有覆盖
要装摄像头的不同的情况:
(1)左右孩子都有覆盖:
即左右孩子都是2
(2)左右孩子至少一个有覆盖
(3)左右孩子至少有一个有摄像头:
此时父节点一定是有覆盖的状态
(4)利用后序遍历,从小往上遍历,如果遍历完了,根节点还是无覆盖状态就在根节点放一个摄像头
cpp
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
int result=0;
int traversal(TreeNode*node)
{
if(node == NULL)return 2;//空结点视为有覆盖
int left = traversal(node->left);
int right = traversal(node->right);
//情况1:左右都有覆盖,说明父节点就是摄像头,不用加
if(left==2&&right==2)return 0;
//情况2:左右至少有一个没被监控到
// left == 0 && right == 0 左右节点无覆盖
// left == 1 && right == 0 左节点有摄像头,右节点无覆盖
// left == 0 && right == 1 左节点有无覆盖,右节点摄像头
// left == 0 && right == 2 左节点无覆盖,右节点覆盖
// left == 2 && right == 0 左节点覆盖,右节点无覆盖
if(left==0||right==0)
{
result++;//放个监控器
return 1;
}
//情况3:左右均已被监控
if(left==1 || right==1)
{
return 2;
}
return -1;//随便给个值,反正不会遍历到这里
}
int minCameraCover(TreeNode* root) {
result=0;
if(traversal(root)==0)//root没被监控到
{
result++;
}
return result;//traversal最终返回的是根节点是否被监控,result在遍历期间进行++
}
};
这题很难,下次我再做一遍,贪心结束啦!