环形加油站问题

参考 LeetCode加油站

一个朴素的思想是二重循环:

  • 对于数组中每个元素作为”起点“,模拟转圈
  • 当转”回来“时返回当前 index
  • 当维护的当前油量不够达到下一个站点时 break 考虑下一个 index

可以写入模拟代码

class Solution {
public:
    int canCompleteCircuit(vector<int>& gas, vector<int>& cost) {
        int cricle_sz = gas.size();
        for (int i =0; i < cricle_sz; ++i){
            int step = 0;
            int curr_gas = 0;
            while(step < cricle_sz) {
                curr_gas += gas[(i + step) % cricle_sz];
                if (curr_gas >= cost[(i + step) % cricle_sz]) {
                    curr_gas -= cost[(i + step) % cricle_sz];
                    step++;
                } else {
                    break;
                }
            }
            if (step == cricle_sz) {
                return i;
            }
        }
        return -1;
    }
};

这个提交可能会存在部分样例超时的情况,主要是没有进行优化:
当从 s 开始,运行到 index i 无法继续前进到 i + 1 时, si 之间每个元素 都 无需考虑作为起点

考虑 ∀ k ∈ [ s , i ] \forall k \in [s, i] k[s,i]

  • 因为能到达 i i i,所以必然能到达 k k k
  • 则到达 k k k 时必有剩余油量 ≥ 0 \geq 0 0,对于 k ∈ [ s , k ] k \in[s,k] k[s,k] 一定成立

故不需要考虑任意子区间 $ [k,i]$,若出现问题直接从 i + 1 作为新起点

注意此处用余数做 index 可能导致重复取值,而每个过不去的 i 只需要考虑一次,因此判断新 i 是否大于旧 i

可写出如下代码

class Solution {
public:
    int canCompleteCircuit(vector<int>& gas, vector<int>& cost) {
        int cricle_sz = gas.size();
        int i = 0;
        while(i < cricle_sz){
            int step = 0;
            int curr_gas = 0;
            while(step < cricle_sz) {
                curr_gas += gas[(i + step) % cricle_sz];
                if (curr_gas >= cost[(i + step) % cricle_sz]) {
                    curr_gas -= cost[(i + step) % cricle_sz];
                    step++;
                } else {
                    break;
                }
            }
            // i = (i + step) % cricle_sz;
            if (step == cricle_sz) {
                return i;
            } else {
                if ((i + step) % cricle_sz + 1 > i) {
                	i = (i + step) % cricle_sz + 1;
            	} else {
                	return -1;
            	}
            }
        }
        return -1;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值