[力扣每日一题]738. 单调递增的数字
给定一个非负整数 N,找出小于或等于 N 的最大的整数,同时这个整数需要满足其各个位数上的数字是单调递增。
(当且仅当每个相邻位数上的数字 x 和 y 满足 x <= y 时,我们称这个整数是单调递增的。)
原题链接
暴力过不去.
贪心算法
题目要求小于等于N的最大单调递增的整数,那么拿一个两位的数字来举例。
例如:98,一旦出现strNum[i - 1] > strNum[i]的情况(非单调递增),首先想让strNum[i - 1]–,然后strNum[i]给为9,这样这个整数就是89,即小于98的最大的单调递增整数。
这一点如果想清楚了,这道题就好办了。
局部最优:遇到strNum[i - 1] > strNum[i]的情况,让strNum[i - 1]–,然后strNum[i]给为9,可以保证这两位变成最大单调递增整数。
全局最优:得到小于等于N的最大单调递增的整数。
但这里局部最优推出全局最优,还需要其他条件,即遍历顺序,和标记从哪一位开始统一改成9。
此时是从前向后遍历还是从后向前遍历呢?
这里其实还有一个贪心选择,对于“遇到strNum[i - 1] > strNum[i]的情况,让strNum[i - 1]–,然后strNum[i]给为9”的情况,这个strNum[i - 1]–的操作应该是越靠后越好。
因为这样才能让这个单调递增整数尽可能的大。例如:对于5486,第一位的5能不减一尽量不减一,因为这个减一对整体损失最大。
所以要从后向前遍历,遇到strNum[i - 1] > strNum[i]的情况,让strNum[i - 1]–,然后strNum[i]给为9,这样保证这个减一的操作尽可能在后面进行(即整数的尽可能小的位数上进行)。
确定了遍历顺序之后,那么此时局部最优就可以推出全局,找不出反例,试试贪心。
class Solution {
public:
int monotoneIncreasingDigits(int N) {
string aa=to_string(N);//int转string函数
int flag=aa.size();
for (int i=aa.size()-1;i>0;i--){
if(aa[i-1]>aa[i]){
flag=i;
aa[i-1]--;
}
}
for(int i=flag;i<aa.size();i++){
aa[i]='9';
}
return stoi(aa); //string转int函数
}
};