描述
在一条环路上有 N 个加油站,其中第 i 个加油站有汽油 gas[i] 升。
你有一辆油箱容量无限的的汽车,从第 i 个加油站开往第 i+1 个加油站需要消耗汽油 cost[i] 升。你从其中的一个加油站出发,开始时油箱为空。
如果你可以绕环路行驶一周,则返回出发时加油站的编号,否则返回 -1。
分析
暴力方法:让每个加油站作为起始结点,遍历一遍,直到找到能够走通全部结点的加油站。时间复杂度是O(n^2)。
for循环适合模拟从头到尾的遍历,而while循环适合模拟环形遍历,要善于使用while!
暴力解法的思路:遍历整个数组,若从i出发然后能够回到i,说明i是起始加油站。
class Solution {
public int canCompleteCircuit(int[] gas, int[] cost) {
int n = gas.length;
for(int i = 0; i < n; i++){
int cur = gas[i];
int index = i;
while(cur >= cost[index]){
cur = cur - cost[index] + gas[(index + 1)%n];
index = (index + 1)%n;
//在while循环内判断,若能够跑一圈,则这个while循环会一直循环下去,所以需要在while内部判断,结束循环。
if(index == i){
return i;
}
}
}
return -1;
}
}
暴力算法的优化:若从i出发最远走到j,则[i~j]之间的加油站都不可能走一圈,最远走到j。
class Solution {
public int canCompleteCircuit(int[] gas, int[] cost) {
int n = gas.length;
for(int i = 0; i < n; i++){
int cur = gas[i];
int index = i;
while(cur >= cost[index]){
cur = cur - cost[index] + gas[(index + 1)%n];
index = (index + 1)%n;
if(index == i){
return i;
}
}
if(index < i){
return -1;
}
i = index;
}
return -1;
}
}
2022-02-05
import java.util.*;
public class Solution {
public int gasStation (int[] gas, int[] cost) {
for(int i = 0; i < gas.length; i++){
if(gas[i] < cost[i]){
continue;
}
int reminds = 0;
int j = i;
while(j != i + gas.length){
reminds += gas[j%gas.length] - cost[j%gas.length];
if(reminds < 0){
break;
}
j++;
}
if(reminds >= 0){
return i;
}
i = --j;
}
return -1;
}
}
贪心算法:计算每个加油站减去消耗后剩余的存量,遍历这些存量,这些存量的和若大于等于0,则能跑一圈,否则不能。
第一步:判断是否能够跑一圈
第二步:能跑一圈则找到起始加油站
起始加油站一定满足:从该加油站的剩余油量开始累加,累加和一直不会小于0,即总是有足够的油量跑到下一站。关键是剩余油量的累加和。操作步骤:
- 计算每一站的剩余油量
- 累加每一站的剩余油量,和若小于0,说明前面不存在起始加油站,则从下一站开始重新累加,直到遍历结束。如存在一个加油站A,从A开始到最后一个加油站剩余油量的累加和大于0,则该加油站A就是起始结点。
证明:
- 因为能跑一圈,所以一定存在起始加油站;
- A前面的加油站剩余油量累加和不能保持大于0,说明从前面的任何一个加油站出发都无法一直走下去。
- 假设A之后的加油站存在一个加油站B,从B出发能够跑一圈。既然从A开始到最后一个加油站剩余油量的累加和大于0,即说明从A出发能够到达A后面的任意一个加油站,所以从B出发能跑一圈,而A又能到达B,所以A也可以是起始加油站。
- 假设A之后的加油站不存在一个加油站B,从B出发能够跑一圈。因为一定存在一个加油站从其出发跑一圈,而A前后都没有一个结点连续跑,所以起始加油站一定是A。
class Solution {
public int canCompleteCircuit(int[] gas, int[] cost) {
int[] remind = new int[gas.length];
int sum = 0;
for(int i = 0; i < gas.length; i++){
remind[i] = gas[i] - cost[i];
sum += remind[i];
}
if(sum < 0){
return -1;
}
int sumtmp = 0;
int index = 0;
for(int i = 0; i < gas.length; i++){
sumtmp += remind[i];
if(sumtmp < 0){
sumtmp = 0;
index = i + 1;
}
}
return index;
}
}
import java.util.*;
public class Solution {
public int gasStation (int[] gas, int[] cost) {
int n = gas.length;
int[] reminds = new int[n];
int sum = 0;
for(int i = 0; i < n; i++){
reminds[i] = gas[i] - cost[i];
sum += reminds[i];
}
if(sum < 0){
return -1;
}
for(int i = 0; i < n; i++){
int accumulation = reminds[i];
if(accumulation < 0){
continue;
}
int j = i++;
while(i < n && accumulation >= 0){
accumulation += reminds[i++];
}
if(i == n){
return j;
}
}
return -1;
}
}