-
题目:
给一个非负整数N,返回一个<=N的最大整数,其从高到低的每位数递增; -
思路:
1.贪心 O(n):n为数字长度 ,O(n) :需要一个数字长度大小的字符串,便于操作
若使用暴力解法,判断N不行就判断N-1,会超时,因此需设法少判断一些数字;
整数N转换为字符串便于操作;
nums[ i ] > num[ i - 1 ],则num[ i - 1 ] --,num[ i ] = ‘9’,例如N=85应返回79;
只能从后往前遍历:①对N的减小最弱,才能找到满足递增的最大整数 ②在遍历过程中可以利用前面修改的结果,而不会破坏前面的工作 ,例如N=220,从前往后边里会返回219,从后往前会返回199;
从后往前遍历过程中,不能直接num[ i ] = ‘9’,而只能flag = i记录下来需要变为9的位置,直到遍历结束,从最靠左的flag开始全置为9(因为一旦一个位置置为‘9’,要想满足递增,后面只能为‘9’)。若直接原地需改,例如 100会被改为90,而不是正确值99
class Solution {
private:
public:
int monotoneIncreasingDigits(int N) {
if (N < 10) return N;
string num = to_string(N);//把整数N转换为字符串。比挨着遍历并用一个vector存好多了
//flag表示最前面需要变为9的位置
//初始值置为这个,表示N直接就是递增的数字
int flag = num.size();
for (int i = num.size() - 1; i > 0; --i) {
if (num[i - 1] > num[i]) {
flag = i;
--num[i - 1];
}
}
for (int i = flag; i < num.size(); ++i) {
num[i] = '9';
}
return stoi(num);//把字符串转换为整数
}
};
2.无敌大佬解法:最多循环9次,我直接原地膜拜
由于结果要求各位数字单调递增,那么这些数字必然形如 a0a1a2……an (1 <= a0 <= a1 <= a2 <= …… <= an <= 9);
由于题目N = [ 0, 10 ^ 9 ],因此不超过N的最大整数最多为9位数;
结果一定是由长度不同的形如111111111的数的和组成;
class Solution {
private:
public:
int monotoneIncreasingDigits(int N) {
int t = 111111111;
int res = 0;
for (int i = 0; i < 9 && t;++i) {
while (res + t > N) t /= 10;
res += t;
}
return res;
}
};
- 总结:
转换为string:to_string;
整数N转换为字符串便于操作;
string[ i ] = ‘9’ 而不是 string[ i ] = 9;
从后往前遍历而不能从前往后:只有从后往前才能重复利用上次比较的结果,且不会破坏之前做的工作;
从后往前遍历过程中,不能直接num[ i ] = ‘9’:只能先 flag = i 记录下来需要变为9的位置,直到遍历结束,从最靠左的flag开始全置为9(因为一旦一个位置置为‘9’,要想满足递增,后面只能为‘9’)。若直接原地需改,例如 N=100,应返回99,而不是90;
string转换为int:int stoi ( const string& ); int atoi (const char* );