一、题目打卡
1.1 单调递增的数字
题目链接:. - 力扣(LeetCode)
// class Solution {
// public:
// bool check(int n, int& pre, int &ind){
// while(n>0){
// int m = n % 10;
// if(m == pre) ind--;
// if(m > pre){
// ind--; // 要不满足递增要求的后一位开始减,如果减去的是m这个位,可能会减多,比如32,减m就是22,实际应该减到29
// return false;
// }
// pre = m;
// n = n / 10;
// ind++;
// }
// return true;
// }
// int monotoneIncreasingDigits(int n) {
// // cout << check(253,3) ? true : false;
// // 这样逻辑没有问题,但是会超时
// // while(n > 0){
// // if(n / 10 == 0) return n;
// // int pre = n % 10;
// // if(check(n,pre)) return n;
// // n--;
// // }
// while(n > 0){
// if(n / 10 == 0) return n;
// int pre = n % 10;
// int ind = 0; // 记录开始不满足递增要求的位数
// if(check(n,pre,ind)) return n;
// else n = n - pow(10,ind);
// // n--;
// }
// return -1;
// }
// };
class Solution {
public:
int monotoneIncreasingDigits(int n) {
if(n / 10 == 0) return n;
string nString = to_string(n);
// bool flag[nString.size()]{false};
int flag = nString.size(); // 标记需要变9的起始位置
for(int i = nString.size() - 1; i > 0; i--){
// 不用一直减,只要标记一下当前位,后面让这个后面都等于9就一定满足
// while(nString[i-1] > nString[i]) nString[i-1]--;
if(nString[i-1] > nString[i]){
nString[i-1]--;
flag = i;
}
}
for(int i = flag;i < nString.size();i++){
nString[i] = '9';
}
return stoi(nString);
}
};
这个题目我想了两种暴力的解法,最简单的思想肯定是不断减 n,直到找到合适的,对于这个减 n 的方法,最粗暴的肯定是每次减1 ,但是不出所料超时,然后我考虑了一种,统计出现不满足递增数字的位置,然后从这个位置开始递减,但是我发现这样其实也会超时,所以看了答案的解法。
答案的思想还是比较巧妙的,我认为理解主要分为两个方面,首先是相邻位置被标记不满足递增条件的位置,其实对于后面那一位来说,直接更新为 9 就可以了,因为这样不管递推到多少步,始终都是满足递增的条件的;其次是需要进行标记的处理,我一开始考虑能不能每次就变成9,但对于 100 这种数字,就会出现最后结果变成 90 的情况,所以其实需要从标记的位置开始一直到最后都要变成 9 ,而且也不能只是在每一次遇到相邻更大的时候直接变9,比如:
for(int i = nString.size() - 1; i > 0; i--){
// 不用一直减,只要标记一下当前位,后面让这个后面都等于9就一定满足
// while(nString[i-1] > nString[i]) nString[i-1]--;
if(nString[i-1] >= nString[i]){
nString[i-1]--;
nString[i] = '9';
// flag = i;
}
}
这样处理不了 101 这种,最后返回的结果会是 91,所以核心的思想其实还是贪心,要让后面所有的都更大。
1.2 监控二叉树(答案思路)
题目链接:. - 力扣(LeetCode)
class Solution {
public:
int res = 0;
int recur(TreeNode* root){
if(!root) return 2; //空节点,标记为已覆盖
int res1 = recur(root->left);
int res2 = recur(root->right);
if(res1 == 2 && res2 == 2){
return 0; // 此节点下面两个节点都被覆盖
}
if(res1 == 0 && res2 == 0){
res++;
return 1; // 此节点下面两个节点都被覆盖
}
if((res1 == 0 && res2 == 1) || (res1 == 1 && res2 == 0)){
res++;
return 1;
}
if(res1 == 1 || res2 == 1) return 2;
// if((res1 == 1 && res2 == 2) || (res1 == 2 && res2 == 1)){
// return 2;
// }
// 2 和 0
if(res1 == 2 || res2 == 2){
res++;
return 1; // 这里装摄像头,
}
return -1; // 不会走到这里
}
int minCameraCover(TreeNode* root) {
int ret = recur(root);
if(!ret) res++; // 这里需要注意,如果说最后头结点返回的是0,说明头结点并没有被覆盖到,所以头结点需要重新+1
return res;
}
};
没写出来,看了答案以后自己写的,感觉这个题目难点在处理二叉树的返回值,其实只要逻辑理清楚了,也不是特别复杂,关键的就是考虑好所有的组合返回去的情况(00 01 02 11 12 22),然后分别处理就行了,有一个细节需要注意的是,如果最后返回的是0,那么说明头结点没有被覆盖到,那么就需要最后的结果上再加1。