第八章 贪心算法 part05
56. 合并区间
本题也是重叠区间问题,如果昨天三道都吸收的话,本题就容易理解了。
别忘了添加最后一个区间
56. 合并区间
class Solution {
public:
static bool cmp(vector<int>& a,vector<int>&b )
{
if(a[0]==b[0])
return a[1]<b[1];
return a[0]<b[0];
}
vector<vector<int>> merge(vector<vector<int>>& intervals) {
vector<vector<int>>result;
if (intervals.empty()) return result;
sort(intervals.begin(), intervals.end(),cmp);
vector<int>path=intervals[0];
for(int i=1;i<intervals.size();i++)
{
if(intervals[i][0]>path[1])
{
result.push_back(path);
path = intervals[i];
}
if(intervals[i][1]>path[1])
{
path[1]=intervals[i][1];
}
}
result.push_back(path);
return result;
}
};
挺简单的一道题,没什么难度。
738. 单调递增的数字
class Solution {
public:
int monotoneIncreasingDigits(int n) {
string strNum = to_string(n);
int flag = strNum.size();
for (int i = strNum.size() - 1; i > 0; i--) {
if (strNum[i - 1] > strNum[i] ) {
flag = i;
strNum[i - 1]--;
}
}
for (int i = flag; i < strNum.size(); i++) {
strNum[i] = '9';
}
return stoi(strNum);
}
};
这题看下答案,代码很简单,思路很简答,但是很不好想出来
最核心的就是:从左到右遍历数字,找到第一对不满足单调递增的数字。
一旦发现不满足条件的情况,将该位数字减1,并将后续的所有位数字设置为9,以保证最终结果仍是最大的可能值。
比如:98,一旦出现strNum[i - 1] > strNum[i]的情况(非单调递增),首先想让strNum[i - 1]–,然后strNum[i]给为9,这样这个整数就是89,即小于98的最大的单调递增整数。
968. 监控二叉树 (可跳过)
本题是贪心和二叉树的一个结合,比较难,一刷大家就跳过吧。
968. 监控二叉树
从下往上看,局部最优:让叶子节点的父节点安摄像头,所用摄像头最少,整体最优:全部摄像头数量所用最少!
空节点不能是无覆盖的状态,这样叶子节点就要放摄像头了,空节点也不能是有摄像头的状态,这样叶子节点的父节点就没有必要放摄像头了,而是可以把摄像头放在叶子节点的爷爷节点上。所以空节点的状态只能是有覆盖,这样就可以在叶子节点的父节点放摄像头了
每个节点可能有几种状态:
有如下三种:
该节点无覆盖
本节点有摄像头
本节点有覆盖
我们分别有三个数字来表示:
0:该节点无覆盖
1:本节点有摄像头
2:本节点有覆盖
本来想着可不可以只用一个bool表示,结果发现不可能,因为要搁置两个放置一个摄像头。我发现回溯的题目都代码比较简单,但是不好想出思路,难度不小
情况1:左右都没摄像头,说明自己肯定无覆盖,return 0;
情况2:只要左右有一个没有覆盖,就赶紧加个摄像头覆盖上,return 1;
情况3:只要左右有一个摄像头,就肯定覆盖,return 2;
试了下,情况一可以和情况2调换顺序,但是情况2的优先级一定大于3,因为先设置摄像头再判断自己能不能被覆盖上,否则就会有的被漏下,监视不到。所以一共有三种排序方式。很厉害
/**
* 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 {
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 0;
if (left == 0 || right == 0) {
result++;
return 1;
}
if (left == 1 || right == 1)
return 2;
return -1;//多个if语句,最后必须有return,否则会报错
}
public:
int minCameraCover(TreeNode* root) {
result = 0;
// 情况4
if (traversal(root) == 0) { // root 无覆盖
result++;
}
return result;
}
};
今天发现一个好的学习方法,就比如这一题,感觉确实有点难度,就一点点啃,一行一行代码背,用笨功夫去学习,要知道自己不是天才,很多题目该不会就是不会,更何况基础薄弱,所以就一点点背,一行行去理解,再两行两行理解,再三行三行理解,花点笨功夫,总能学会的呢。
总结
可以看看贪心算法的总结,贪心本来就没啥规律,能写出个总结篇真的不容易了。
贪心的难题又真的有点难,贪心也没有什么框架和套路。局部最优推导到全局最优,代码随想录卡尔牛逼。