LeetCode 134、加油站

106 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第24天,点击查看活动详情

题目:在一条环路上有n个加油站,规定第i个加油站里面有gas[i]升汽油。

现在有一辆不限定油箱容量的车,从第i个加油站开往下一个加油站需要耗费cost[i]升汽油,开始时油箱为空,可以选择从其中一个加油站出发。

给定加油站油量数组和耗费汽油数组,判断是否可以从其中一个加油站绕环路行驶一周,如果可以返回开始加油站编号,否则返回-1。

解题思路

本题使用暴力解法还是很简单的,我们只需要从头往后遍历,只要满足gas[i]>=cost[i],那必然可以作为起点,之后判断作为起点是否可以回到这个点即可,判断的方法是按照题目规则不断更新步伐和油量,依次循环,如果最终都没有满足条件的则返回-1。可得代码如下:

public int canCompleteCircuit(int[] gas, int[] cost) {
    for(int i=0;i<gas.length;i++){
        if(gas[i]>=cost[i]&&canComplete(gas, cost, i)) return i;
    }
    return -1;
}

public boolean canComplete(int[] gas, int[] cost, int start){
    int curGas = gas[start];
    int i = start;
    while(curGas>=cost[i]){
        curGas += gas[(i+1)%gas.length] - cost[i];
        i = (i+1)%gas.length;
        if(i==start) return true;
    }
    return false;
}

此方法的时间复杂度很高,达到了O(n2)O(n^2),最终在一个长案例那超时,无法通过。

转换思路,如果当前加油站的油量小于去往下一站的所需油量,那此站必然不可能可以作为起点,而如果我们从头到尾汽油总和减去需要耗费汽油总和,那必然可以满足绕圈的要求,因此我们只需要在不满足作为起点时更新起点和油量即可。可得代码如下:

public int canCompleteCircuit2(int[] gas, int[] cost) {
    int start = 0;
    int curSum = 0;
    int totalSum = 0;
    for(int i=0;i<gas.length;i++){
        curSum += gas[i]-cost[i];
        totalSum += gas[i] - cost[i];
        if(curSum<0){
            start = i+1;
            curSum = 0;
        }
    }
    if(totalSum<0) return -1;
    return start;
}

最终时间复杂度为O(n)O(n)