加油站
描述
在一条环路上有 N 个加油站,其中第 i 个加油站有汽油 gas[i] 升。
你有一辆油箱容量无限的的汽车,从第 i 个加油站开往第 i+1 个加油站需要消耗汽油 cost[i] 升。你从其中的一个加油站出发,开始时油箱为空。
如果你可以绕环路行驶一周,则返回出发时加油站的编号,否则返回 -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 可为起始索引。
思路
暴力搜索,以每一个加油站为起点,检查从该加油站出发,是否可以完成一圈。
gas_count:走到第K个站点,剩余油量
如果gas_count<0,说明无法到达下一个站点
因为可能走了已经超过一圈,需要确定当前在第几个站点。可以通过 (出发站点+走过的站点个数)除以 站点总个数 得到的余数确定当前所处的站点位置。
即:k=(i+j)%n
实现
public class Main {
//遍历每个加油站,检查以该加油站为起点,是否能走过一圈
public static int canCompleteCircuit(int[] gas, int[] cost) {
int n=gas.length;
//遍历每个加油站
for (int i = 0,j=0; i < n; i++) {
int count=0;
//j 记录走过的站点个数,n个是一圈
for (j = 0; j < n; j++) {
//确定第几站
//出发点+走过的站点个数 除以总数,余数就是当前站点位置
int k=(i+j)%n;
//剩余油量
count+=gas[k]-cost[k];
if (count<0){
break;
}
}
//如果已经走了一圈了说明i点符合条件
if (j>=n){
return i;
}
}
return -1;
}
}
优化
当以第 i 个加油站为出发点时,经过了 j 个站点后到达K站点,在前往下一个站点时失败了,那么在 i 到达K站点时,途径的所有站点,以其中任意一个站点为起点,都会在K站点失败。
因此,跳过这些会失败的站点,避免重复走,从 第i+j+1的站点处重新出发,检查之后的站点是否可以完成一圈。
public class T134_1 {
public static int canCompleteCircuit(int[] gas, int[] cost) {
int n=gas.length;
//优化:当以 i 为出发点时,经过了 j 站点,在 k 站点处失败了,
//那么途径的任一个站点为起点到该点同样会失败,
//因此直接跳过这些失败的站点,从 i+j+1 处重新开始
//以i站点为起点
for (int i = 0,j=0; i < n; i+=j+1) {
int count=0;
//j 记录走过的站点个数,n个是一圈
for (j = 0; j < n; j++) {
//确定第几站,加油站是环形的
//出发点+走过的站点个数 除以总数,余数就是当前站点位置
int k=(i+j)%n;
//剩余油量
count+=gas[k]-cost[k];
if (count<0){
break;
}
}
//如果已经走了一圈了说明i点符合条件
if (j>=n){
return i;
}
}
return -1;
}
}