738.单调递增的数字
这道题的主要是考察规律的把握,要注意到小于目标数的最大递增数字在首个不符合位置减1,然后后面的位置都自动变为9,看起来简单,但是有一些小点要注意:
- 一定倒序遍历,因为如果正序遍历的话没法处理like 332 (答案是299)这样的数字的,处理到第一个3的时候不会减1,因为是符合要求的,如果正序就会得到329,因为第二位数字减1了,所以它的前一位数字不能确定是否还小于它了,而倒序遍历就避免这样的情况。倒序遍历会先得到322,这样保证了被比较的那一位(这里第二位)一定是更新过后的,所以因此不能只修改一处不符合条件的就break了,而是要一直更新(一遇到不符合的就更新),更新了之后再继续往前遍历。
- 记得及时更新flag(标记第一位前后比较不符合的后的位置,这也是9开始的位置)。
int monotoneIncreasingDigits(int N) {
string strNum = to_string(N);
// flag用来标记赋值9从哪里开始
// 设置为这个默认值,为了防止第二个for循环在flag没有被赋值的情况下执行
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);
}
968.监控二叉树
本题是贪心和二叉树的一个结合,比较难,一刷大家就跳过吧。
这道题文章里面确实写得很清楚,节点的状态一共分成三种:
- 无覆盖,对应返回值0 。
- 有摄像头,对应返回值1 。
- 有覆盖,孩子节点或父节点(倒序遍历只需看孩子节点)有摄像头,对应返回值2 。
不能一遇到无覆盖,就在当前节点放置摄像头,而是需要在它的父节点上设置摄像头,这样才能实现摄像头的最大利用,而其他情况不需要放置摄像头。那么自然叶子节点是不适合放摄像头的,所以遍历到空节点的时候,必须要返回有覆盖2,当前叶子节点才会返回0,于是才会使得叶子节点的父节点放置摄像头。这道题的遍历顺序也很重要,想要得知当前节点是否应该放置摄像头需要知道它的左右孩子节点的情况,故而只能后序遍历。
需要注意的是,一旦子孩子节点出现无覆盖的情况就需要在当前节点放置摄像头,而不必两个孩子都是无覆盖,毕竟当前节点不放置,那这个孩子节点就永远都不会被监控了。还有因为原则是一旦当前节点为无覆盖,就在它的父节点上放置摄像头,但是遇到根节点的时候就不能这样了(根节点无覆盖是没有父节点放摄像头的),所以最后必须单独看根节点是否覆盖。
class Solution {
public:
int sum=0; // 0-无覆盖 1-有摄像头 2-有覆盖
int traversal(TreeNode* root){
if(root==NULL) return 2;
int left=traversal(root->left);
int right=traversal(root->right);
if(left==0||right==0) {
sum++;
return 1;
}
if(left==1||right==1) {
return 2;
}
return 0;
}
int minCameraCover(TreeNode* root) {
if(traversal(root)==0) sum++;
return sum;
}
};
总结
可以看看贪心算法的总结,贪心本来就没啥规律,能写出个总结篇真的不容易了。
- 如果找出局部最优并可以推出全局最优,就是贪心,如果局部最优都没找出来,就不是贪心,可能是单纯的模拟。
- 股票系列问题用贪心也可以解决,不只是动规的专长。
- 在出现两个维度相互影响的情况时,两边一起考虑一定会顾此失彼,要先确定一个维度,再确定另一个一个维度。