参考 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
时, s
到 i
之间每个元素 都 无需考虑作为起点
考虑 ∀ 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;
}
};