贪心算法--进阶

前言

上篇文章对一些基础的贪心算法题进行解释,(详细内容请跳转到此篇)那么本篇文章将在那基础上做出升级,同样也是列出三道贪心算法题。

题型训练

加油站

力扣题目链接
题目

在一条环路上有 n 个加油站,其中第 i 个加油站有汽油 gas[i] 升。 你有一辆油箱容量无限的的汽车,从第 i 个加油站开往第i+1 个加油站需要消耗汽油 cost[i] 升。你从其中的一个加油站出发,开始时油箱为空。 给定两个整数数组 gas 和 cost,如果你可以按顺序绕环路行驶一周,则返回出发时加油站的编号,否则返回 -1 。如果存在解,则 保证 它是 唯一 的。
示例 输入: gas= [1,2,3,4,5], cost = [3,4,5,1,2]
输出: 3

分析

从全局思考,要想油能够跑完一周,那么他的总油量一定大于消耗的油量。
再从局部开始思考,什么情况不可以作为起始:假设起始位置为i,当到达某一个加油站j时,油箱的油量不能满足消耗时,那么【i,j】这个区间都不足以满足要求,起始位置就要从j+1开始。

在这里插入图片描述

代码实现

	  int res=0;//局部剩余
      int totalres=0;//总剩余量
      int index=0;//起始位置下标
      for(int i=0;i<gas.size();i++)
      {
        totalres+=gas[i]-cost[i];
        res+=gas[i]-cost[i];
        if(res<0)
        {
            index=i+1;
            res=0;
        }
      }
      if(totalres<0) return -1;
      else
      return index;

分发糖果

力扣题目链接
题目

n 个孩子站成一排。给你一个整数数组 ratings 表示每个孩子的评分。
你需要按照以下要求,给这些孩子分发糖果:
每个孩子至少分配到 1 个糖果。
相邻两个孩子评分更高的孩子会获得更多的糖果。
请你给每个孩子分发糖果,计算并返回需要准备的 最少糖果数目 。
输入:ratings = [1,0,2]
输出:5
解释:你可以分别给第一个、第二个、第三个孩子分发 2、1、2 颗糖果。

分析

我们试着从左往右遍历:高分孩子糖果多,那么我们遇到高分孩子,就让他比前一个孩子糖果多一。例如:

在这里插入图片描述

例如

但我们不难发现,这样遍历以后,后三个孩子糖果分配不正确,这就要求我们再从有往左遍历,查缺补漏。

在这里插入图片描述

代码实现

vector<int> candyVec(ratings.size(), 1);//糖果初始化为1,数组大小为小孩人数
        //从左开始遍历
        for (int i = 1; i < ratings.size(); i++) {
            if (ratings[i] > ratings[i - 1]) candyVec[i] = candyVec[i - 1] + 1;
        }
        //从右开始遍历
        for (int i = ratings.size() - 2; i >= 0; i--) {
            if (ratings[i] > ratings[i + 1] ) {
                candyVec[i] = max(candyVec[i], candyVec[i + 1] + 1);
            }
        }
        int result = 0;
        for (int i = 0; i < candyVec.size(); i++) result += candyVec[i];
        return result;

合并区间

力扣题目链接
题目

以数组 intervals 表示若干个区间的集合,其中单个区间为 intervals[i] = [starti, endi]
。请你合并所有重叠的区间,并返回 一个不重叠的区间数组,该数组需恰好覆盖输入中的所有区间 。
示例 1:
输入:intervals = [[1,3],[2,6],[8,10],[15,18]] 输出:[[1,6],[8,10],[15,18]]
解释:区间 [1,3] 和 [2,6] 重叠, 将它们合并为 [1,6].

分析

首先我们要会判断区间重合,紧接着我们再去合并
就如图所示,找到重合区间只在前两个集合中存在,我们就只将前两个合集合并,取最大的区间【1,6】

在这里插入图片描述

那我们在实现代码的时候如何判断呢?
1.先让集合以左边界从小到大排序
2.从排序后第一个集合开始,将右边界与下一个左边界相比较判断是否存在重合,如果存在(即右边界>左边界),那就将第一个集合的有边界更新为当前比较的两个集合中右边界最大的一个
(例如,图中右边界6>3,所以直接将第一个集合右边界更新为6);如果不存在,那就判断下一个集合。(也就是往后寻找【8,10】集合的重合区间)

代码实现

        vector<vector<int>> result;
        if(intervals.size()==0) return result;//直接返回空集合
        sort(intervals.begin(),intervals.end(),[](const vector<int>&a,const vector<int>b)
        {
            return a[0]<b[0];
        }); //排序
        result.push_back(intervals[0]);
        for(int i=1;i<intervals.size();i++)
        {
            if(result.back()[1]>=intervals[i][0])
            result.back()[1]=max(intervals[i][1],result.back()[1]);//有重叠
            else
            result.push_back(intervals[i]);
        }
        return result;

关于贪心算法的题目我们就更新到这里啦。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值