文章目录
题目
标题和出处
标题:单调递增的数字
出处:738. 单调递增的数字
难度
5 级
题目描述
要求
一个整数是单调递增的,当且仅当每一对相邻位的数字 x \texttt{x} x 和 y \texttt{y} y 满足 x ≤ y \texttt{x} \le \texttt{y} x≤y。
给定一个整数 n \texttt{n} n,返回小于等于 n \texttt{n} n 且单调递增的最大数字。
示例
示例 1:
输入: n = 10 \texttt{n = 10} n = 10
输出: 9 \texttt{9} 9
示例 2:
输入: n = 1234 \texttt{n = 1234} n = 1234
输出: 1234 \texttt{1234} 1234
示例 3:
输入: n = 332 \texttt{n = 332} n = 332
输出: 299 \texttt{299} 299
数据范围
- 0 ≤ n ≤ 10 9 \texttt{0} \le \texttt{n} \le \texttt{10}^\texttt{9} 0≤n≤109
解法
思路和算法
如果整数 n n n 已经单调递增,则答案即为 n n n。如果整数 n n n 不满足单调递增,则答案小于 n n n。
为了方便处理,将整数 n n n 转换成字符数组 array \textit{array} array,然后遍历字符数组 array \textit{array} array 计算小于等于 n n n 且单调递增的最大数字。为了得到单调递增的数字,其对应的字符数组 array \textit{array} array 必须单调递增。
从右到左遍历 array \textit{array} array,对于遍历到的每个下标 i i i,如果 array i > array i + 1 \textit{array}i > \textit{array}i + 1 arrayi>arrayi+1,则 array \textit{array} array 不满足单调递增,且在不减少 array i \textit{array}i arrayi 的情况下无法使 array \textit{array} array 满足从下标 i i i 到末尾的子数组单调递增。为了使 array \textit{array} array 满足从下标 i i i 到末尾的子数组单调递增,可以执行如下操作。
-
将 array i \textit{array}i arrayi 减 1 1 1。
-
将 array \textit{array} array 从下标 i + 1 i + 1 i+1 到末尾的数字全部设为 9 9 9。
此时 array \textit{array} array 从下标 i i i 到末尾的每一位都取可能的最大值,因此 array \textit{array} array 表示的整数为小于 n n n 且满足从下标 i i i 到末尾的子数组单调递增的最大整数。
更新 array \textit{array} array 从下标 i i i 到末尾的数字之后,继续向左遍历,对于遍历到的每个下标执行该操作,遍历到最高位之后,即可得到小于等于 n n n 且单调递增的最大数字。特别地,如果对于任意下标 i i i 都有 array i ≤ array i + 1 \textit{array}i \le \textit{array}i + 1 arrayi≤arrayi+1,则整数 n n n 已经单调递增,答案是 n n n。
实现方面,当 array i \textit{array}i arrayi 减少时,并不需要立即更新 array \textit{array} array 从下标 i + 1 i + 1 i+1 到末尾的数字,而是可以找到被修改的最高位下标,遍历结束之后将被修改的最高位右边的数字全部设为 9 9 9 即可。
根据上述分析,可以使用贪心的思想计算小于等于 n n n 且单调递增的最大数字。
-
用 startIndex \textit{startIndex} startIndex 表示 array \textit{array} array 中被修改的最高位下标,初始时 startIndex = − 1 \textit{startIndex} = -1 startIndex=−1。从右到左遍历 array \textit{array} array,对于每个下标 i i i,如果 array i > array i + 1 \textit{array}i > \textit{array}i + 1 arrayi>arrayi+1,则将 array i \textit{array}i arrayi 减 1 1 1 并将 startIndex \textit{startIndex} startIndex 更新为 i i i。
-
遍历结束之后,如果 startIndex ≥ 0 \textit{startIndex} \ge 0 startIndex≥0 则将 array \textit{array} array 从下标 startIndex + 1 \textit{startIndex} + 1 startIndex+1 到末尾的数字全部设为 9 9 9。
-
此时 array \textit{array} array 对应的数字为小于等于 n n n 且单调递增的最大数字。
代码
java
class Solution {
public int monotoneIncreasingDigits(int n) {
char[] array = String.valueOf(n).toCharArray();
int numLength = array.length;
int startIndex = -1;
for (int i = numLength - 2; i >= 0; i--) {
if (array[i] > array[i + 1]) {
array[i]--;
startIndex = i;
}
}
if (startIndex >= 0) {
for (int i = startIndex + 1; i < numLength; i++) {
array[i] = '9';
}
}
return Integer.parseInt(new String(array));
}
}
复杂度分析
-
时间复杂度: O ( log 10 n ) O(\log_{10} n) O(log10n),其中 n n n 是给定的整数。整数 n n n 的位数是 O ( log 10 n ) O(\log_{10} n) O(log10n),最多需要遍历整数两次。
-
空间复杂度: O ( log 10 n ) O(\log_{10} n) O(log10n),其中 n n n 是给定的整数。需要创建长度为 O ( log 10 n ) O(\log_{10} n) O(log10n) 的数组记录每一位数字。