代码随想录算法训练营
—day31
文章目录
前言
今天是算法营的第31天,希望自己能够坚持下来!
今日任务:
● 56. 合并区间
● 738.单调递增的数字
● 968.监控二叉树
一、 56. 合并区间
思路:
1.先对区间以左边界进行排序
2.遍历区间,重叠的就对区间进行合并,更新右边界;不重叠的直接放入结果集
这里有个技巧,把第一个区间直接放入结果集,然后遍历的时候直接在结果集中进行合并区间
class Solution {
public:
// static bool cmp(const vector<int>& a, const vector<int>& b) {
// return a[0] < b[0];
// }
vector<vector<int>> merge(vector<vector<int>>& intervals) {
vector<vector<int>> result;
if (intervals.size() == 0) return result;
//用lambda表达式
sort(intervals.begin(), intervals.end(), [](const vector<int>& a, const vector<int>& b) {return a[0]<b[0];});
//第一个区间直接放入结果集,之后在结果集中进行合并
result.push_back(intervals[0]);
for (int i = 1; i < intervals.size(); i++) {
if (intervals[i][0] <= result.back()[1]) { //重叠
//合并区间,就是更新结果集里面的右边界,左边界已经按大小排序了,只有右边界需要判断取最大值
result.back()[1] = max(intervals[i][1], result.back()[1]);
} else {
result.push_back({intervals[i][0], intervals[i][1]}); //不重叠
}
}
return result;
}
};
二、738. 单调递增的数字
思路:
- 将数字转成字符串来处理
- 后序遍历,如果左边数字比当前数字大,记录当前数字位置flag,并且左边数字-1
- 记录的flag及以后的数字都变成9
代码如下:
class Solution {
public:
int monotoneIncreasingDigits(int n) {
string s = to_string(n); //转成字符串来处理
int flag = s.size(); //记录需要变成9的数字位置
for (int i = s.size() - 1; i > 0; i--) { //后序遍历,一直到第二个数字
if (s[i - 1] > s[i]) { //左边数字比右边大
flag = i;
s[i - 1]--; //左边的数字-1,后面的数字全部变成9
}
}
//flag位置及后面的数字全部变成9
for (int i = flag; i < s.size(); i++) {
s[i] = '9';
}
return stoi(s);
}
};
三、968.监控二叉树
思路:
整体思路是让叶子节点的父节点放监控,可以覆盖到叶子节点和父节点的父节点两层。
定义二叉树节点的三种状态:
0.无覆盖
1.有监控
2.有覆盖
思考空节点是什么状态:
空节点需要返回2有覆盖,因为空节点如果返回0和1都会影响“让叶子节点的父节点放监控”这个最初的设定。
思考遍历顺序:
需要左右节点反馈结果给中间节点,使用后序遍历。
递归三部曲:
1.递归的参数和返回值:参数是节点,返回值是自定义的三种节点状态(0,1,2)
2.终止条件:遇到空节点终止。
3.单层递归逻辑:
有三种情况:
情况一:左右节点都有覆盖,那么当前节点无覆盖,需要当前节点的父节点放监控,返回0
情况二:左右任一节点无覆盖,那么当前节点都需要放监控,返回1(result++)
情况三:左右任一节点有监控,那么当前节点就是有覆盖,返回2
还有一种情况,情况四:到根节点的时候返回的是无覆盖,本来需要在当前节点的父节点放监控的,但是根节点已经没有父节点了,那么需要在根节点也放一个监控。
代码如下:
/**
* 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:无覆盖,1:有摄像头 2:有覆盖
//叶子节点往上遍历,使用后序遍历(左右中)
//叶子节点的父节点放摄像头
int traversal(TreeNode* root) {
//空节点返回2有覆盖
if (root == nullptr) return 2;
int left = traversal(root->left);
int right = traversal(root->right);
//1.左右节点都有覆盖,当前节点无覆盖,返回0(父节点安装摄像头)
if (left == 2 && right == 2) return 0;
//2.左右节点任意一个无覆盖,当前节点安装摄像头,返回1
if (left == 0 || right == 0) {
result++;
return 1;
}
//3.左右节点任意一个有摄像头,当前节点有覆盖,返回2
if (left == 1 || right == 1) return 2;
return -1;
}
int minCameraCover(TreeNode* root) {
result = 0;
//4.根节点返回0,本来需要在其父节点安装摄像头来覆盖的,需要加多一个摄像头在根节点
if (traversal(root) == 0) result++;
return result;
}
};
总结
贪心算法终于结束了,之前没接触过贪心算法,学完这一章后受益匪浅。每次看题目都会不禁“啊?”,然后看完题解又会有种茅塞顿开的感觉!
明天继续加油!