代码随想录算法训练营第二十七天任务
- [56. 合并区间](#56. 合并区间)
- 738.单调递增的数字
- 968.监控二叉树
56. 合并区间
思路:当遇到intervals[i][0] > end 将之前的start, end存储起来,更新start,end; 当重叠时,更新end.
cpp
class Solution {
public:
vector<vector<int>> merge(vector<vector<int>>& intervals) {
sort(intervals.begin(), intervals.end());
int start = intervals[0][0];
int end = intervals[0][1];
vector<vector<int>> res;
for (int i = 1; i < intervals.size(); ++i) {
if (intervals[i][0] > end) {
res.push_back({start, end});
start = intervals[i][0];
}
if (intervals[i][1] > end) {
end = intervals[i][1];
}
}
res.push_back({start, end}); // 最后一个区间数组
return res;
}
};
时间复杂度:O(n log n)
空间复杂度:O(n) 排序
738.单调递增的数字
看题解了,从后往前遍历。
让我想起了135. 分发糖果这道题从右向左遍历时的情景。
cpp
class Solution {
public:
int monotoneIncreasingDigits(int n) {
string strNum = to_string(n);
int flag = strNum.size(); // 记录哪一位是从 9 开始的. eg: 1000 不能初始化0或者-1,
for (int i = strNum.size() - 1; i >= 1; --i) {
if (strNum[i - 1] > strNum[i]) { // 出现递减
strNum[i - 1]--;
strNum[i] = '9';
flag = i;
}
}
for (int i = flag + 1; i < strNum.size(); ++i) {
strNum[i] = '9';
}
return atoi(strNum.c_str());
}
};
时间复杂度:O(n)
空间复杂度:O(n) 字符串空间
968.监控二叉树
这道题相当困难。看题解了。
自己再写一下思路,加强理解。
首先是叶子节点肯定不放摄像头,这样能保证最少的摄像头数量。(叶子节点是指数级别的增长)
在层上,每隔两个放一个摄像头
树的遍历方式:后序遍历(左右后)
对于监控二叉树的节点,有三种状态:有摄像头,有覆盖,无覆盖。
用1表示有摄像头
用2表示有覆盖
用3表示无覆盖
如果遇到空节点,肯定不是有摄像头,如果是无覆盖,那么叶子节点就要有摄像头(想象一个节点 左孩子 和 右孩子 只有其中一个),所以空节点的状态应该是有覆盖。
cpp
/*
用 1 表示有摄像头
用 2 表示有覆盖
用 3 表示无覆盖 : 叶子节点,父节点有摄像头
*/
class Solution {
int result = 0;
int traversal(TreeNode* cur) {
if (cur == nullptr) return 2; // 空节点表示有覆盖。
int left = traversal(cur->left);
int right = traversal(cur->right);
// 左右节点都有覆盖
if (left == 2 && right == 2) return 3;
// 左右节点至少有一个是无覆盖,父节点就要放摄像头
if (left == 3 || right == 3) {
result++;
return 1;
}
// 左右节点任一一个有摄像头, 父节点就是有覆盖
if (left == 1 || right == 1) return 2;
return -1; // 逻辑不会走到这里,只是函数需要个返回值。
}
public:
int minCameraCover(TreeNode* root) {
if (traversal(root) == 3) { // 如果头节点无覆盖,就需要加摄像头
result++;
}
return result;
}
};
这道题有意思。
时间复杂度:O(n) 需遍历每个节点
空间复杂度:O(n) 递归栈深度