记录新手小白的抄题过程。
在一条环路上有 n 个加油站,其中第 i 个加油站有汽油 gas[i] 升。
你有一辆油箱容量无限的的汽车,从第 i 个加油站开往第 i+1 个加油站需要消耗汽油 cost[i] 升。你从其中的一个加油站出发,开始时油箱为空。
给定两个整数数组 gas 和 cost ,如果你可以绕环路行驶一周,则返回出发时加油站的编号,否则返回 -1 。如果存在解,则 保证 它是 唯一 的。
第一次做:
排个序,先把需要的最多气的给走了 ,把获得的油可以满足的最大的距离先满足
暴力解法:
class Solution {
public:
int canCompleteCircuit(vector<int>& gas, vector<int>& cost) {
for (int i = 0; i < cost.size(); i++) {
int rest = gas[i] - cost[i]; // 记录剩余油量
int index = (i + 1) % cost.size();
while (rest > 0 && index != i) { // 模拟以i为起点行驶一圈
rest += gas[index] - cost[index];
index = (index + 1) % cost.size();//它是按要求跑的一圈,是固定的
}
// 如果以i为起点跑一圈,剩余油量>=0,返回该起始位置
if (rest >= 0 && index == i) return i;
}
return -1;
}
};
通过暴力解法了解题目,但是超出时间限制 。
全局算法
class Solution {
public:
int canCompleteCircuit(vector<int>& gas, vector<int>& cost) {
int curSum = 0;
int min = INT_MAX; // 从起点出发,油箱里的油量最小值
for (int i = 0; i < gas.size(); i++) {
int rest = gas[i] - cost[i];
curSum += rest;
if (curSum < min) {
min = curSum;
}
}
if (curSum < 0) return -1; // 情况1
if (min >= 0) return 0; // 情况2
// 情况3
for (int i = gas.size() - 1; i >= 0; i--) {
int rest = gas[i] - cost[i];
min += rest;
if (min >= 0) {
return i;
}
}
return -1;
}
};
理解一下这个代码发出的三个情况
- 首先总数小于所有的和
- 如果有一些最小的都是大于0的(之前一直从0开始)
- 第三种情况,如果累加的最小值是负数,汽车就要从非0节点出发,从后向前,看哪个节点能这个负数填平,能把这个负数填平的节点就是出发节点。从为负的开始
第三点如何理解
上面的理解不了
贪心算法:
class Solution {
public:
int canCompleteCircuit(vector<int>& gas, vector<int>& cost) {
int curSum = 0;
int totalSum = 0;
int start = 0;
for (int i = 0; i < gas.size(); i++) {
curSum += gas[i] - cost[i];
totalSum += gas[i] - cost[i];
if (curSum < 0) { // 当前累加rest[i]和 curSum一旦小于0,贪心的步骤,在此之前积累的油没法满足这一次的行程,即前面的i个位置都不能开头,开头也没法满足
start = i + 1; // 起始位置更新为i+1
curSum = 0; // curSum从0开始
}
}
if (totalSum < 0) return -1; // 说明怎么走都不可能跑一圈了
return start;
}
};
思路:我们意识到其实遍历所有车站的顺序是固定的,我们只是需要找到起点的位置,确保在耗油量最大的路程中,前面积累的油能够支撑他们走完这一程
开始,两个总和,一共是用来记录走到半路的和,因为我们在半路走到小于0时就说明这条路走不下去需要重新开始,而为了保证一定走得完,需要一个和记录是否所有油的量是大于需要消耗的油量的。
理解一下//我不理解为什么第二个条件存在的意义
第二次做:
第二次看到这个题依旧完全不会呀