记录新手小白的抄题过程。
当且仅当每个相邻位数上的数字 x 和 y 满足 x <= y 时,我们称这个整数是单调递增的。
给定一个整数 n ,返回 小于或等于 n 的最大数字,且数字呈 单调递增 。
示例 1:
输入: n = 10
输出: 9
示例 2:输入: n = 1234
输出: 1234
示例 3:输入: n = 33
输出: 299
理解题目意思,一个逐渐大于等于递增的数,小于等于n
题目要求小于等于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的最大单调递增的整数。
这个思想绝妙
此时是从前向后遍历还是从后向前遍历呢?
从前向后遍历的话,遇到strNum[i - 1] > strNum[i]的情况,让strNum[i - 1]减一,但此时如果strNum[i - 1]减一了,可能又小于strNum[i - 2]。
这么说有点抽象,举个例子,数字:332,从前向后遍历的话,那么就把变成了329,此时2又小于了第一位的3了,真正的结果应该是299。
所以从前后向遍历会改变已经遍历过的结果!
class Solution {
public:
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);
}
};
想一想为什么需要一个来记录有9的出现位置
我自己想了想,写成这样行不行呢?
class Solution {
public:
int monotoneIncreasingDigits(int n) {
string s=to_string(n);
//int flag=0;
for(int i=s.size()-1;i>0;i--){
if(s[i-1]>s[i]){
s[i-1]--;
s[i]='9';
}
}
return stoi(s);
}
};
这样是不行的,因为只有后面所有为9才是最大的。如果i-1<i,但是i-2>i-1,则i-1改成9,但不保证i是9,不一定递增递减,所以需要记录。
且注意flag的初始化要为size(),意味着若原数就是递增,则不需要改数据为9
知识点:
十进制转化字符串,字符串转化十进制