今天继续学习贪心算法解决相关问题。
738.单调递增的数字
当且仅当每个相邻位数上的数字 x 和 y 满足 x <= y 时,我们称这个整数是单调递增的。
给定一个整数 n ,返回 小于或等于 n 的最大数字,且数字呈 单调递增 。
示例 1:
输入: n = 10
输出: 9
示例 2:
输入: n = 1234
输出: 1234
示例 3:
输入: n = 332
输出: 299
思路:
1.首先,由于题目给出的就是一个整数,要想判断每一位上的数字是否递增可能想到要额外写一个函数用来拆分各个位上的数字再进行比较,这样会比较复杂。首先想到将整数转化成字符串,这样比较方便比较每一位上的数字。
2.然后就是本题一个比较核心的思路:如何保证单调递增的最大数字呢?通过示例2和示例3给出的例子。可以想到除非数字本身就是单调递增,那么它自己就是最大的;否则就尽量让单调递增的后面尽可能多的出现9。
3.再通过多举几个例子更进一步思考,我们可以遍历整个字符串,当前一位数字大于当前位置数字时,我们就将前一位数字减1,并将当前位置赋为9,这样似乎就可以达到我们想要的结果了。
class Solution {
public:
int monotoneIncreasingDigits(int n) {
string str = to_string(n);
int flag = str.size();//记录最后一次把数字改为9的位置
for(int i = str.size()- 1; i > 0; i--){
//前一位数字大于当前位置数字,将前一位数字减1并记录当前位置数字要改为9
if(str[i - 1] > str[i]){
str[i - 1] --;
flag = i;
}
}
//借助保存的最后一次改为9的位置,将该位置之后的所有元素全部改为9
for(int i = flag; i < str.size(); i++){
str[i] = '9';
}
return stoi(str);
}
};
启发:
1.本题避开了暴力解法中额外写一个拆分各个位上的数字判断是否单调递增的复杂,直接采取前一个位置数字比当前位置数字大时将前一位数字减1并且将当前位置数字置为9,保证了最终结果的单调递增性。这种解法需要进一步理解。
2.本题的遍历顺序十分有讲究,如果是从前往后遍历,拿332举例子,如果从前往后遍历,按照我们的思路最后求得的数字是329,但此时2又比3小了,不能满足题意;所以我们一定要从后向前遍历,这样才能保证让本次遍历是在上次遍历的结果之上进行的。
3.还有一点需要注意的是,本题并没有在单次递归发现前一个位数字比当前位的数字小就直接将当前位置的数字置为9,而是用一个整型变量记录了最后一个需要置为9的数字的位置,然后将该位之后的所有数字全部置为9。
拿3322举例子,如果直接在单次遍历过程中就将当前位置数字置为9,最后我们得到的结果是2992,显然并不满足题意,最终结果应当是2999。
之所以出现这样的情况是因为从后往前遍历的过程中有可能前一位数字小于等于当前位数字,但在后续的遍历过程中出现了大于的情况,在发生这种情况时我们将当前位置数字置为9,但是在这之前遍历的所有数字我们都没有置为9。因此我们需要用整型变量存储实际上最后一个需要置为9的数字的位置,并从该位置开始将之后的所有数字全部置为9以满足最终的单调递增。