当前位置: 首页 > news >正文

LeetCode 134. 加油站(函数图像法 / 贪心)

题目:

链接:LeetCode 134. 加油站
难度:中等

在一条环路上有 n 个加油站,其中第 i 个加油站有汽油 gas[i] 升。

你有一辆油箱容量无限的的汽车,从第 i 个加油站开往第 i+1 个加油站需要消耗汽油 cost[i] 升。你从其中的一个加油站出发,开始时油箱为空。

给定两个整数数组 gas 和 cost ,如果你可以绕环路行驶一周,则返回出发时加油站的编号,否则返回 -1 。如果存在解,则 保证 它是 唯一 的。

示例 1:

输入: gas = [1,2,3,4,5], cost = [3,4,5,1,2]
输出: 3
解释:
从 3 号加油站(索引为 3 处)出发,可获得 4 升汽油。此时油箱有 = 0 + 4 = 4 升汽油
开往 4 号加油站,此时油箱有 4 - 1 + 5 = 8 升汽油
开往 0 号加油站,此时油箱有 8 - 2 + 1 = 7 升汽油
开往 1 号加油站,此时油箱有 7 - 3 + 2 = 6 升汽油
开往 2 号加油站,此时油箱有 6 - 4 + 3 = 5 升汽油
开往 3 号加油站,你需要消耗 5 升汽油,正好足够你返回到 3 号加油站。
因此,3 可为起始索引。

示例 2:

输入: gas = [2,3,4], cost = [3,4,3]
输出: -1
解释:
你不能从 0 号或 1 号加油站出发,因为没有足够的汽油可以让你行驶到下一个加油站。
我们从 2 号加油站出发,可以获得 4 升汽油。 此时油箱有 = 0 + 4 = 4 升汽油
开往 0 号加油站,此时油箱有 4 - 3 + 2 = 3 升汽油
开往 1 号加油站,此时油箱有 3 - 3 + 3 = 3 升汽油
你无法返回 2 号加油站,因为返程需要消耗 4 升汽油,但是你的油箱只有 3 升汽油。
因此,无论怎样,你都不可能绕环路行驶一周。

提示:

  • gas.length == n
  • cost.length == n
  • 1 <= n <= 105
  • 0 <= gas[i], cost[i] <= 104

方法一:

函数图像法:

在这里插入图片描述
sum 代表路途中油箱的油量,如果把这个「最低点」作为起点,即把这个点作为坐标轴原点,就相当于把图像「最大限度」向上平移了:
在这里插入图片描述
如果经过平移后图像全部在 x 轴以上,就说明可以行使一周。

代码一:

class Solution {
public:int canCompleteCircuit(vector<int>& gas, vector<int>& cost) {int n = gas.size();int minsum = 0, minpos = 0; //函数最低点的值,函数最低点的坐标(出发站编号)int sum = 0;for(int i = 0; i < n; i++){sum += gas[i] - cost[i];if(sum < minsum) {minsum = sum;minpos = i + 1;}}if(sum < 0) return -1;return minpos % n;}
};

时间复杂度O(n),空间复杂度O(1)。

方法二:

贪心解法:

用贪心思路解决这道题的关键在于以下这个结论:

如果选择站点i作为起点「恰好」无法走到站点j,那么i和j中间的任意站点k都不可能作为起点。

比如说,如果从站点1出发,走到站点5时油箱中的油量「恰好」减到了负数,那么说明站点1「恰好」无法到达站点5;那么你从站点2,3,4任意一个站点出发都无法到达5,因为到达站点5时油箱的油量也必然被减到负数。

如何证明这个结论?

假设sum记录当前油箱中的油量,如果从站点i出发(sum = 0),走到j时恰好出现sum < 0的情况,那说明走到i, j之间的任意站点k时都满足sum > 0,对吧。

如果把k作为起点的话,相当于在站点k时sum = 0,那走到j时必然有sum < 0,也就是说k肯定不能是起点。

拜托,从i出发走到k好歹sum > 0,都无法达到j,现在你还让sum = 0了,那更不可能走到j了对吧。

综上,这个结论就被证明了。

回想一下我们开头说的暴力解法是怎么做的?

如果我发现从i出发无法走到j,那么显然i不可能是起点。

现在,我们发现了一个新规律,可以推导出什么?

如果我发现从i出发无法走到j,那么i以及i, j之间的所有站点都不可能作为起点。

看到冗余计算了吗?看到优化的点了吗?

这就是贪心思路的本质,如果找不到重复计算,那就通过问题中一些隐藏较深的规律,来减少冗余计算。

代码二:

class Solution {
public:int canCompleteCircuit(vector<int>& gas, vector<int>& cost) {int n = gas.size();for(int i = 0; i < n;){int sum = 0;bool flag = true; //以i为出发站时能否环行一周for(int j = i; j < i + n; j++){sum += gas[j % n] - cost[j % n]; //行至第j+1个加油站时,油箱内的油量if(sum < 0) {if(j + 1 >= n) return -1; //全部出发点已遍历完,未找到可行解i = (j + 1) % n; //无法从第i站到第j+1站,则从中间任意一站都无法到第j+1站。那么以第j+1站为出发站继续检查flag = false;break;}}if(flag) return i; //以第i站为出发站可以走完一周,返回i}return -1;}
};

时间复杂度O(n),空间复杂度O(1)。

http://www.lryc.cn/news/38676.html

相关文章:

  • 王道计算机组成原理课代表 - 考研计算机 第三章 存储系统 究极精华总结笔记
  • Flask-mock接口数据流程
  • springboot项目配置序列化,反序列化器
  • c++11 标准模板(STL)(std::unordered_map)(九)
  • Seay代码审计工具
  • 界面开发(4)--- PyQt5实现打开图像及视频播放功能
  • 核心系统国产平台迁移验证
  • 【数据结构之二叉树】——二叉树的概念及结构,特殊的二叉树和二叉树性质
  • Android学习之帧动画和视图动画
  • vue2和vue3的区别
  • 【你不知道的事】JavaScript 中用一种更先进的方式进行深拷贝:structuredClone
  • XE开发Linux应用(二)-Webservice
  • kubernetes实战与源码学习
  • CNCF x Alibaba云原生技术公开课 第八章 应用配置管理
  • YUV实践记录
  • 【题解】百度2020校招Web前端工程师笔试卷(第一批):单选题、多选题
  • 探索云原生技术之容器编排引擎-kubeadm安装kubernetes1.21.10(新版:针对高版本内核)
  • 2023广西自治区职业技能大赛“网络安全” 项目比赛任务书
  • Reactor模式
  • Git图解-IDEA中的Git操作
  • 在一个web应用中应该如何完成资源的跳转
  • 前缀和部分题目
  • 三天吃透MySQL面试八股文
  • Giving You A guide to learning any topic faster than 95% of people
  • (七十七)大白话MySQL是如何根据成本优化选择执行计划的?(中)
  • 原来CSS 也可以节流啊
  • UE官方教程笔记03-功能、术语、操作简介
  • BN,LN,IN,GN的理解和用法
  • Linux:epoll模式web服务器代码,代码debug
  • SpringSecurity学习(四)密码加密、RememberMe记住我