代码随想录算法学习心得 32 | 738.单调递增的数字、贪心算法总结

一、单调递增的数字

链接:力扣

描述:当且仅当每个相邻位数上的数字 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(动态数组),效率会高很多。

 贪心解决区间问题:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值