力扣-738. 单调递增的数字
1.题目
题目地址(738. 单调递增的数字 - 力扣(LeetCode))
https://leetcode.cn/problems/monotone-increasing-digits/
题目描述
当且仅当每个相邻位数上的数字 x
和 y
满足 x <= y
时,我们称这个整数是单调递增的。
给定一个整数 n
,返回 小于或等于 n
的最大数字,且数字呈 单调递增 。
示例 1:
输入: n = 10 输出: 9
示例 2:
输入: n = 1234 输出: 1234
示例 3:
输入: n = 332 输出: 299
提示:
0 <= n <= 109
2.题解
2.1 贪心算法
思路
首先我们从高位到低位,尽可能的使结果与初始值n相同(对应位数值相同)
当遇到第一个不能满足递增条件的位i时(nums[i-1] > nums[i]),我们回退到i-1, 并将该位数值-1,
此时不管后面的位数值为多少,都肯定是满足 结果<初始值,为了争取最大值,我们可以将后面所有值设置为9, 比如像234999(235->234,后面999) < 235212
但是还需要注意的是,由于这里我们将nums[i] -= 1, 回退了一个数字,可能导致之前满足的递增序列不再成立,所以我们需要进行回溯
比如像: 232999(233 -> 232) < 233211, 但是这里232已经不满足递增序列了
所以我们要继续回溯 229999 < 232999 < 233211 (23 -> 22),
且由于原先的数列是递增数列,这里nums[i]--导致递增不满足,也只会是数值相差1的这一种情况(所以回溯过程中只要进行nums[i - 1] -= 1;即可,不需要考虑具体回溯多少)
可以发现,我们只要进行回溯,判断在尽可能贴近原数值的情况下,确定最后一个满足递增序列的位置i即可,[0,i]保持原数值,[i+1,len)选择'9'
代码
- 语言支持:C++
C++ Code:
class Solution {
public:
int monotoneIncreasingDigits(int n) {
string nums = to_string(n), ans;
int i = 1, len = nums.length();
while (i < len && nums[i - 1] <= nums[i])
i++;
// 说明中途暂停了,有不满足的条件, 有nums[i-1] > nums[i]
if (i < len) {
while (i > 0 && nums[i - 1] > nums[i]) {
nums[i - 1] -= 1;
i--;
}
// 此时又回到了nums[i - 1] <= nums[i], i之后的所有都不满足,直接改为9即可
while (++i < len)
nums[i] = '9';
}
int num = stoi(nums);
return num;
}
};
复杂度分析
令 n 为数组长度。
- 时间复杂度:\(O(n)\)
- 空间复杂度:\(O(n)\)