在一个环形路径上分布着n个加油站,从一个加油站到下一个加油站会耗油。要找出一个起始点,从这个起始点出发,存油量>=耗油量。解保证唯一。
这要求在路径上不能出现非负的。
如果找出存油量最大的子序列,则可确保尽可能走完全程(贪心思想)。
因此,需要在环形数组中找一个最大子序列和。最大子序列和是很经典的DP问题,而针对环形约束,采用的是将数组复制一份并放到原数组最后,然后采用普通的最大子序列求解。其间,需要记录起始位置(这是最终要求的),走过的站点数(站点数不能超过n,这是环形数组,长度为2n),最大的子序列和。在长度大于n的时候,需要向后调整起始位置,需要满足起始位置不为负数。
复杂度O(2n)=>O(n)
class Solution {
public:
int canCompleteCircuit(vector<int> &gas, vector<int> &cost) {
vector<int>vt(gas.size()*2);
int i,mx=-1,sum=0,n=gas.size();
for(i=0;i<n;++i){
vt[i]=vt[i+n]=gas[i]-cost[i];
sum+=vt[i];
}
if(sum<0)return -1;
int m=n*2,j=0,st=0,mst=-1,step=0;
sum=0;
for(i=0;i<m&&st<n;++i){
sum+=vt[i];
++step;
if(sum<0){
step=0;sum=0;st=i+1;
continue;
}
if(step>n){
j=st;sum-=vt[j++],step--;
while(j<i&&vt[j]<0)sum-=vt[j++],step--;
st=j;
}
if(sum>mx){
mx=sum,mst=st;
}
}
return mst;
}
};
环形数组的最大子序列和问题这里介绍了采用求非环形数组的最大子序列maxv和和最小子序列和minv,然后环形数组最大子序列和答案为max(maxv,total-minv),如果是total-minv值更大,则其实位置为最小子序列和的终止位置的下一个位置。
int canCompleteCircuit(vector<int> &gas, vector<int> &cost) {
int i,mx=0,sum=0,n=gas.size(),d,sum2=0,mn=0,end=0,tot=0,start=0,mst=0;
for(i=0;i<n;++i){
d=gas[i]-cost[i];
sum+=d;
tot+=d;
if(sum<0){
sum=0;start=i+1;
}
if(sum>mx){
mx=sum;mst=start;
}
sum2+=d;
if(sum2>0){
sum2=0;
}
if(sum2<mn){
mn=sum2;
end=i;
}
}
return tot<0?-1:(tot-mn>mx?(end+1)%n:mst);
}