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

简介: 代码随想录算法训练营第三十六天 | 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 代码

//
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. 监控二叉树,不仅贪心的思路不好想,而且需要对二叉树的操作特别娴熟,这就是典型的交叉类难题了。
相关文章
|
2月前
|
算法
Leetcode 初级算法 --- 数组篇
Leetcode 初级算法 --- 数组篇
43 0
|
1月前
|
存储 算法 Java
leetcode算法题-有效的括号(简单)
【11月更文挑战第5天】本文介绍了 LeetCode 上“有效的括号”这道题的解法。题目要求判断一个只包含括号字符的字符串是否有效。有效字符串需满足左括号必须用相同类型的右括号闭合,并且左括号必须以正确的顺序闭合。解题思路是使用栈数据结构,遍历字符串时将左括号压入栈中,遇到右括号时检查栈顶元素是否匹配。最后根据栈是否为空来判断字符串中的括号是否有效。示例代码包括 Python 和 Java 版本。
|
1月前
|
算法 Python
在Python编程中,分治法、贪心算法和动态规划是三种重要的算法。分治法通过将大问题分解为小问题,递归解决后合并结果
在Python编程中,分治法、贪心算法和动态规划是三种重要的算法。分治法通过将大问题分解为小问题,递归解决后合并结果;贪心算法在每一步选择局部最优解,追求全局最优;动态规划通过保存子问题的解,避免重复计算,确保全局最优。这三种算法各具特色,适用于不同类型的问题,合理选择能显著提升编程效率。
50 2
|
2月前
|
算法 Java C++
【贪心算法】算法训练 ALGO-1003 礼物(C/C++)
【贪心算法】算法训练 ALGO-1003 礼物(C/C++)
【贪心算法】算法训练 ALGO-1003 礼物(C/C++)
|
4月前
|
算法
测试工程师的技能升级:LeetCode算法挑战与职业成长
这篇文章通过作者亲身体验LeetCode算法题的过程,探讨了测试工程师学习算法的重要性,并强调了算法技能对于测试职业成长的必要性。
80 1
测试工程师的技能升级:LeetCode算法挑战与职业成长
|
3月前
|
算法 前端开发
一文了解贪心算法和回溯算法在前端中的应用
该文章深入讲解了贪心算法与回溯算法的原理及其在前端开发中的具体应用,并通过分析LeetCode题目来展示这两种算法的解题思路与实现方法。
|
4月前
|
算法 Java
LeetCode经典算法题:矩阵中省份数量经典题目+三角形最大周长java多种解法详解
LeetCode经典算法题:矩阵中省份数量经典题目+三角形最大周长java多种解法详解
57 6
|
4月前
|
存储 算法 Java
LeetCode经典算法题:打家劫舍java详解
LeetCode经典算法题:打家劫舍java详解
76 2
|
4月前
|
人工智能 算法 Java
LeetCode经典算法题:井字游戏+优势洗牌+Dota2参议院java解法
LeetCode经典算法题:井字游戏+优势洗牌+Dota2参议院java解法
54 1
|
4月前
|
存储 算法 Java
LeetCode经典算法题:预测赢家+香槟塔java解法
LeetCode经典算法题:预测赢家+香槟塔java解法
65 1