一、单调递增的数字
链接:力扣
描述:当且仅当每个相邻位数上的数字 x 和 y 满足 x <= y 时,我们称这个整数是单调递增的。
给定一个整数 n ,返回 小于或等于 n 的最大数字,且数字呈 单调递增 。
思路如下:题目要求小于等于N的最大单调递增的整数,先举个例子。
例如:98,一旦出现strNum[i - 1] > strNum[i]的情况(非单调递增),首先想让strNum[i - 1]--,然后strNum[i]给为9,这样这个整数就是89,即小于98的最大的单调递增整数。
如果是从前向后遍历的话,无法利用到之前遍历的结果,,遇到strNum[i - 1] > strNum[i]的情况,让strNum[i - 1]减一,但此时如果strNum[i - 1]减一了,可能又小于strNum[i - 2]。
例如332,从前向后遍历的话,那么就把变成了329,此时2又小于了第一位的3了,真正的结果应该是299。那么从后向前遍历,就可以重复利用上次比较得出的结果了,从后向前遍历332的数值变化为:332 -> 329 -> 299
确定了遍历顺序之后,那么此时局部最优就可以推出全局,可以使用贪心算法。需要先将给的n转化为字符串,用to_string方法。注意其中的flag的使用,初始化为s.size(),因为如果s本身就是递增的顺序,此时不需要进行处理,直接返回,因此需要初试化为s.size()。
代码如下:
class Solution {
public:
int monotoneIncreasingDigits(int n)
{
string s = to_string(n);
int flag = s.size();//记录需要变成9的位置
for (int i = s.size() - 1; i > 0; i--)
{
//注意i不能等于0
if (s[i - 1] > s[i])
{
s[i - 1]--;
flag = i;
}
}
for (int i = flag; i < s.size(); i++)
{
s[i] = '9';
}
return stoi(s);
}
};
运行如下:
二、贪心算法总结
贪心的本质是选择每一阶段的局部最优,从而达到全局最优。
贪心的套路:无固定的套路而言,关键在于如何通过局部最优达到全局最优?如果找不到合适的反例去反驳,就可以用贪心试试,但不需要进行理论的证明。
面试中基本不会让面试者现场证明贪心的合理性,代码写出来跑过测试用例即可,或者自己能自圆其说理由就行了。刷题或者面试的时候,手动模拟一下感觉可以局部最优推出整体最优,而且想不到反例,那么就试一试贪心。
贪心一般解题步骤:
贪心算法一般分为如下四步:
将问题分解为若干个子问题。
找出适合的贪心策略。
求解每一个子问题的最优解。
将局部最优解堆叠成全局最优解。
做题的时候,只要想清楚局部最优是什么,如果推导出全局最优,其实就够了。
简单题:
中等题:
贪心算法解决股票问题:
存在两个维度的问题 :
在出现两个维度相互影响的情况时,两边一起考虑一定会顾此失彼,要先确定一个维度,再确定另一个维度。模拟插队的时候,使用C++中的list(链表)替代了vector(动态数组),效率会高很多。
贪心解决区间问题: