问题描述

当且仅当每个相邻位数上的数字 x 和 y 满足 x <= y 时,我们称这个整数是单调递增的。

给定一个整数 n ,返回 小于或等于 n 的最大数字,且数字呈 单调递增 。

示例 1:

输入: n = 10
输出: 9

示例 2:

输入: n = 1234
输出: 1234

示例 3:

输入: n = 332
输出: 299

提示:

  • 0 <= n <= 10^9

核心思路

核心思路

strN[i]\textit{strN}[i] 表示数字 nn 从高到低的第 ii 位的数字(ii00 开始)。

  • 如果整个数字 nn 本身已经是按位单调递增的,那么最大的数字即为 nn

  • 如果找到第一个位置 ii 使得 [0,i1][0,i-1] 的数位单调递增且 strN[i1]>strN[i]\textit{strN}[i-1]>\textit{strN}[i],此时 [0,i][0,i] 的数位都与 nn 的对应数位相等,仍然被 nn 限制着,即我们不能随意填写 [i+1,k1][i+1,k-1] 位置上的数字。为了得到最大的数字,我们需要解除 nn 的限制,来让剩余的低位全部变成 99 ,即能得到小于 nn 的最大整数。而从贪心的角度考虑,我们需要尽量让高位与 nn 的对应数位相等,故尝试让 strN[i1]\textit{strN}[i-1] 自身数位减 11。此时已经不再受 nn 的限制,直接将 [i,k1][i, k-1] 的位置上的数全部变为 99 即可。

实现要点

strN[i1]\textit{strN}[i-1] 自身数位减 11 后可能会使得 strN[i1]\textit{strN}[i-1]strN[i2]\textit{strN}[i-2] 不再满足递增的关系,因此我们需要从 i1i-1 开始递减比较相邻数位的关系,直到找到第一个位置 jj 使得 strN[j]\textit{strN}[j] 自身数位减 11strN[j1]\textit{strN}[j-1]strN[j]\textit{strN}[j] 仍然保持递增关系,或者位置 jj 已经到最左边(即 jj 的值为 00),此时我们将 [j+1,k1][j+1,k-1] 的数全部变为 99 才能得到最终正确的答案。

code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class Solution {
public:
int monotoneIncreasingDigits(int n) {
string strN = to_string(n);
int i = 1;
while (i < strN.length() && strN[i - 1] <= strN[i]) {
i += 1;
}
if (i < strN.length()) {
while (i > 0 && strN[i - 1] > strN[i]) {
strN[i - 1] -= 1;
i -= 1;
}
for (i += 1; i < strN.length(); ++i) {
strN[i] = '9';
}
}
return stoi(strN);
}
};
  • 时间复杂度:O(logn)O(\log n),其中 O(logn)O(\log n) 表示数字 nn 的位数。我们遍历 O(logn)O(\log n) 的时间即能构造出满足条件的数字。

  • 空间复杂度:O(logn)O(\log n)。我们需要 O(logn)O(\log n) 的空间存放数字 nn 每一位的数字大小。