【贪心算法】加油站,单调递增的数字,坏了的计算器,合并区间,用最少数量的箭引爆气球

1. 加油站(LC 134)

加油站

题目描述

解题思路

枚举

枚举所有起点,判断是否能绕一周。可以用diff数组记录每个加油站收入与支出,从diff为正数的位置开始枚举

贪心优化

假设i为起点,到j位置油量小于零,由于起点的收益一定是正数,如果从i+1位置开始,到j位置的剩余油量一定更小,也就不可能到j位置。因此下一次枚举可以从j开始尝试。

代码实现

  • 枚举(超时)
java 复制代码
public int canCompleteCircuit(int[] gas, int[] cost) {
        int n = gas.length;
        int[] diff = new int[n];
        for(int i = 0;i<n;i++)
            diff[i] = gas[i]-cost[i];

        for(int i = 0;i<n;i++){
            if(diff[i]>=0){
                int step = 0;
                int rest = 0;
                int j = i;
                boolean flag = true;
                while(step<n){
                    rest+=diff[j];
                    if(rest<0){
                        flag = false;
                        break;
                    }
                    j = j+1<n?j+1:0;
                    step++;
                }
                if(flag)
                    return i;
            }
        }
        return -1;
    }
  • 贪心
java 复制代码
public int canCompleteCircuit(int[] gas, int[] cost) {
        int n = gas.length;
        int[] diff = new int[n];
        for(int i = 0;i<n;i++)
            diff[i] = gas[i]-cost[i];

        for(int i = 0;i<n;i++){
            if(diff[i]>=0){
                int step = 0;
                int rest = 0;
                int j = i;
                boolean flag = true;
                while(step<n){
                    rest+=diff[j];
                    if(rest<0){
                        flag = false;
                        break;
                    }
                    j = j+1<n?j+1:0;
                    step++;
                }
                if(flag)
                    return i;
                i+=step;
            }
        }
        return -1;
    }

2. 单调递增的数字(LC 738)

单调递增的数字

题目描述

解题思路

  1. 如果高位递增,不需要修改
  2. 从左向右找到不递增的位置,让它-1,后面的数都填9.
  3. 如果遇到一段相同的数字,例如1245554321修改成12345549999,还需要再把前面的5改成4,这里可以用递归的思想,直到修改成递增的数字。

代码实现

java 复制代码
public int monotoneIncreasingDigits(int n) {
        char[] num = (n+"").toCharArray();
        int len = num.length;
        boolean flag = true;
        for(int i = 0;i<len-1;i++){
            if(num[i]>num[i+1]){
                flag = false;
                num[i] -=1;
                for(int j = i+1;j<len;j++)
                    num[j] = '9';
                break;
            }
        }
        int ret = Integer.parseInt(new String(num));
        if(flag)
            return ret;
        else
            return monotoneIncreasingDigits(ret);
    }

3. 坏了的计算器(LC 991)

坏了的计算器

题目描述

解题思路

正难则反

把target转换成startValue,进行+1或/2操作

  1. 如果s>=t只能进行加法操作,两数之差就是操作次数
  2. 如果s<t,要分类讨论
    • 如果当前是奇数,只能+1
    • 如果当前是偶数,优先/2

代码实现

java 复制代码
public int brokenCalc(int startValue, int target) {
        int ret = 0;        
        while(target>startValue){
            if(target%2 == 0)
                target/=2;
            else
                target+=1;
            ret++;
        }
        ret+=startValue-target;

        return ret;
    }

4. 合并区间(LC 56)

合并区间

题目描述

解题思路

先按左端点排序,后面依次判断能否合并。创建一个ArrayList<Integer>保存结果

  • 如果当前的数组和Arrlist的最后一个数组存在重叠区域,直接合并,右端点取两者的最大值
  • 如果不重叠,添加新数组

补充语法知识:

  1. CollectiontoArray()方法:
    • Object[] toArray():返回包装集合数组,不能强转成int[][]
    • <T> T[] toArray(T[] a):将集合转换为指定类型的数组。
      • 如果参数数组的大小小于集合,会创建一个新的数组,且类型相同,大小与集合相等。伊因此可以直接传入int[0][]
  2. int[] last = list.getLast()last拿到了list最后一个元素的引用,对last 修改就可以直接修改list

代码实现

java 复制代码
public int[][] merge(int[][] intervals) {
        int n = intervals.length;
        Arrays.sort(intervals,(a,b)->Integer.compare(a[0],b[0]));

        ArrayList<int[]> list = new ArrayList<>();
        list.add(intervals[0]);

        for(int i=1;i<n;i++){
            int[] last = list.getLast();
            if(intervals[i][0]<=last[1])
               last[1] = Math.max(intervals[i][1],last[1]);
            else
                list.add(intervals[i]);
        }

        int[][] ret = list.toArray(new int[list.size()][2]);
        return ret;
    }

5. 无重叠区间(LC 435)

无重叠区间

题目描述

解题思路

对左端点排序,比较右端点,如果有重叠,保留右端点更小的区间,舍弃右端点更大的区间。

右端点可以用一个变量维护

代码实现

java 复制代码
public int eraseOverlapIntervals(int[][] intervals) {
        Arrays.sort(intervals,(a,b)->Integer.compare(a[0],b[0]));
        int n = intervals.length;

        int ret = 0;
        int last = intervals[0][1];
        for(int i = 1;i<n;i++){
            if(intervals[i][0]<last){
                last = Math.min(last,intervals[i][1]);
                ret++;
            }else
                last = intervals[i][1];
        }
        return ret;
    }

6. 用最少数量的箭引爆气球(LC 452)

用最少数量的箭引爆气球

题目描述

解题思路

  1. 按左端点排序
  2. 找出两个区间的交集,与下一个区间比较,如果下一个区间与前面的交集重叠,则证明可以共用一个箭,因为是取交集,右端点取最小值;否则说明需要新的箭,更新右端点。

代码实现

java 复制代码
public int findMinArrowShots(int[][] points) {
        int n = points.length;
        Arrays.sort(points,(a,b)->Integer.compare(a[0],b[0]));
        int ret = 1;
        int right = points[0][1];
        for(int i = 1;i<n;i++){
            if(points[i][0]<=right)
                right = Math.min(points[i][1],right);
            else{
                ret++;
                right = points[i][1];
            }
        }
        return ret;
    }
相关推荐
小O的算法实验室2 小时前
IEEE TASE,基于MPC的多无人机协同搜索竞争群体优化方法
算法
Tbisnic3 小时前
BGE-M3 算法详解:从模型架构到三种检索方式的数学原理
算法·自然语言处理·大模型·bert·transformer·注意力机制
Brilliantwxx4 小时前
【算法从零到千】【55-58】哈希位图+常见数学运算 接口
算法
空堂与归5 小时前
用户分群找不到规律?用K-Means聚类算法自动发现数据模式
算法·机器学习·kmeans·聚类
动词ing5 小时前
【C语言】自定义函数+指针入门
c语言·开发语言·算法
重生之后端学习5 小时前
283. 移动零[简单]✅
开发语言·数据结构·算法·leetcode·职场和发展
一只小小的芙厨6 小时前
基础数论总结
笔记·学习·算法
夜不会漫长7 小时前
C++入门(1)
开发语言·c++·算法
wen_zhufeng8 小时前
IndexTTS 2.5 技术报告
人工智能·算法·机器学习
大熊背9 小时前
树莓派相机自动白平衡详解(四)
算法·树莓派·白平衡·isppipeline