代码随想录算法训练营第三十六天 | LeetCode 738. 单调递增的数字、贪心算法总结

代码随想录算法训练营第三十六天 | LeetCode 738. 单调递增的数字、贪心算法总结

文章链接:单调递增的数字 贪心算法总结

视频链接:单调递增的数字

1. LeetCode 738. 单调递增的数字

1.1 思路

  1. 本题的贪心思路是什么?举个例子 32,这不是一个单调递增的数字,那就要处理后再返回了,十位上的 3一定要-1,它如果不变的话,就无法处理,因为要返回一个<=32 的数,3->2 后,个位上的 2 就可以变大了,直接 2->9,最终返回29
  2. 大体思路:如果发现两位不符合单调递增前一位小于等于后一位的情况要做处理时,就要对前一位-1,后一位再变为 9。
  3. 那我们要从前往后遍历还是从后往前遍历呢?拿 332 举例,如果从前往后,比较到十位和个位时,整体从332->329,但此时百位和十位又不对了,因为后面处理完的值可能是比前面的值小的,没有重复利用到前面的比较结果。如果从后往前遍历,比较到十位和个位时,整体从332->329,再比较百位和十位时,整体从 329->299,这样能得到我们要的结果是因为从后往前遍历时是能够利用到后面遍历过的结果的
  4. 为了方便遍历,把 n 变为字符数组char[] chars=(n+"").toCharArray()。再定义个 start 标记从哪个位置开始往后遍历将数值变为 9,初始化为 chars.length,初始化为这个是因为如果数字本身就是单调递增的就不用更改数值
  5. for(int i=chars.length-1;i>0;i++)这里 i 不能等于 0 是因为后面是 i-1 和 i 比较,等于 0 会越界,然后是处理逻辑,if(chars[i-1]>chars[i])即前面一位大于当前一位时,就要将前一位-1,chars[i-1]--,然后用 start=i 标记一下位置,后面处理 start 后面的数位都变为 9
  6. 上面处理完就要更新数值 9 了,for(int i=start;i<chars.length;i++)chars[i]='9'。
  7. 这里可能疑惑,为什么不在上面第一个循环里就把数值变为 9 呢?举例 1000,我们这里比较处理的逻辑只发生在千位和百位的"10",只会变为了"09",整体就是变为了"0900"而我们要的是"999"
  8. 最后将这个 char[] 转为 String 后再转为 int

1.2 代码

java 复制代码
//
class Solution {
    public int monotoneIncreasingDigits(int n) {
        char[] chars=(n+"").toCharArray();
        int start=chars.length;
        for(int i=chars.length-1;i>0;i--){
            if(chars[i-1]>chars[i]){
                chars[i-1]--;
                start=i;
            }
        }
        for(int i=start;i<chars.length;i++){
            chars[i]='9';
        }
        return Integer.parseInt(new String(chars));
    }
}

贪心算法总结

2.1 理论基础

  1. 贪心很简单,就是常识?
    贪心思路往往很巧妙,并不简单
  2. 贪心有没有固定的套路?
    无套路,也没有框架,只能多练
  3. 什么题目是贪心呢?

观点来自程序员Carl:如果找出局部最优并可以推出全局最优,就是贪心,如果局部最优都没找出来,就不是贪心,可能是单纯的模拟。但学会解题就行

  1. 如何知道局部最优推出全局最优,有数学证明么?

观点来自程序员Carl:在做贪心题的过程中,如果再来一个数据证明,其实没有必要,手动模拟一下,如果找不出反例,就试试贪心。面试中,代码写出来跑过测试用例即可,或者自己能自圆其说理由就行了

2.2 贪心简单题

以下三道题目就是简单题,大家会发现贪心感觉就是常识。是的,如下三道题目,就是靠常识,但也得具体分析局部最优是什么,全局最优是什么,贪心也要贪的有理有据。

  1. 455. 分发饼干
  2. 1005. K 次取反后最大化的数组和
  3. 860. 柠檬水找零

2.3 贪心中等题

贪心中等题,靠常识可能就有点想不出来了。开始初现贪心算法的难度与巧妙之处

  1. 376. 摆动序列
  2. 738. 单调递增的数字
2.3.1 贪心解决股票问题

大家都知道股票系列问题是动规的专长,其实用贪心也可以解决,而且还不止就这两道题目,但这两道比较典型。

  1. 122. 买卖股票的最佳时机 II
  2. 714. 买卖股票的最佳时机含手续费
2.3.2 两个维度权衡问题

在出现两个维度相互影响的情况时,两边一起考虑一定会顾此失彼,要先确定一个维度,再确定另一个一个维度。

  1. 135. 分发糖果
  2. 406. 根据身高重建队列

2.4 贪心难题

这里的题目如果没有接触过,其实是很难想到的,甚至接触过,也一时想不出来,所以题目不要做一遍,要多练!

2.4.1 贪心解决区间问题

关于区间问题,各种覆盖各种去重。

  1. 55. 跳跃游戏
  2. 45. 跳跃游戏 II
  3. 452. 用最少数量的箭引爆气球
  4. 435. 无重叠区间
  5. 763. 划分字母区间
  6. 56. 合并区间
2.4.2 其他难题
  1. 最大子数组和其实是动态规划的题目,但贪心性能更优,很多同学也是第一次发现贪心能比动规更优的题目。
  2. 134. 加油站可能以为是一道模拟题,但就算模拟其实也不简单,需要把while用的很娴熟。但其实是可以使用贪心给时间复杂度降低一个数量级。
  3. 最后贪心系列压轴题目968. 监控二叉树,不仅贪心的思路不好想,而且需要对二叉树的操作特别娴熟,这就是典型的交叉类难题了。
相关推荐
逝去的秋风4 分钟前
【代码随想录训练营第42期 Day61打卡 - 图论Part11 - Floyd 算法与A * 算法
算法·图论·floyd 算法·a -star算法
zero_one_Machel13 分钟前
leetcode73矩阵置零
算法·leetcode·矩阵
青椒大仙KI111 小时前
24/9/19 算法笔记 kaggle BankChurn数据分类
笔记·算法·分类
^^为欢几何^^1 小时前
lodash中_.difference如何过滤数组
javascript·数据结构·算法
豆浩宇1 小时前
Halcon OCR检测 免训练版
c++·人工智能·opencv·算法·计算机视觉·ocr
浅念同学1 小时前
算法.图论-并查集上
java·算法·图论
何不遗憾呢1 小时前
每日刷题(算法)
算法
立志成为coding大牛的菜鸟.1 小时前
力扣1143-最长公共子序列(Java详细题解)
java·算法·leetcode
鱼跃鹰飞1 小时前
Leetcode面试经典150题-130.被围绕的区域
java·算法·leetcode·面试·职场和发展·深度优先
liangbm31 小时前
数学建模笔记——动态规划
笔记·python·算法·数学建模·动态规划·背包问题·优化问题