我们可以从高到低按位构造这个小于等于 n 的最大单调递增的数字。假设不考虑 n 的限制,那么对于一个长度为 k 的数字,最大单调递增的数字一定是每一位都为 9 的数字。
记 strN}[i] 表示数字 n 从高到低的第 i 位的数字(i 从 0 开始)。
如果整个数字 n 本身已经是按位单调递增的,那么最大的数字即为 n。
如果找到第一个位置 i 使得 [0,i-1] 的数位单调递增且 strN}[i-1]>\textit{strN}[i],此时 [0,i] 的数位都与 n 的对应数位相等,仍然被 n 限制着,即我们不能随意填写 [i+1,k-1] 位置上的数字。为了得到最大的数字,我们需要解除 n 的限制,来让剩余的低位全部变成 9 ,即能得到小于 n 的最大整数。而从贪心的角度考虑,我们需要尽量让高位与 n 的对应数位相等,故尝试让 strN}[i-1] 自身数位减 1。此时已经不再受 n 的限制,直接将 [i, k-1] 的位置上的数全部变为 9 即可。
classSolution { public: intmonotoneIncreasingDigits(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'; } } returnstoi(strN); } };
[sol1-Java]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
classSolution { publicintmonotoneIncreasingDigits(int n) { char[] strN = Integer.toString(n).toCharArray(); inti=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 Integer.parseInt(newString(strN)); } }
[sol1-JavaScript]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
var monotoneIncreasingDigits = function(n) { const strN = n.toString().split('').map(v => +v); let 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; } } returnparseInt(strN.join('')); };
[sol1-Golang]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
funcmonotoneIncreasingDigits(n int)int { s := []byte(strconv.Itoa(n)) i := 1 for i < len(s) && s[i] >= s[i-1] { i++ } if i < len(s) { for i > 0 && s[i] < s[i-1] { s[i-1]-- i-- } for i++; i < len(s); i++ { s[i] = '9' } } ans, _ := strconv.Atoi(string(s)) return ans }