leetcode :Gas Station

There are N gas stations along a circular route, where the amount of gas at station i is gas[i].

You have a car with an unlimited gas tank and it costs cost[i] of gas to travel from station i to its next station (i+1). You begin the journey with an empty tank at one of the gas stations.

Return the starting gas station's index if you can travel around the circuit once, otherwise return -1.

Note:
The solution is guaranteed to be unique.

下面常规思路超时:遍历每个节点,以当前i节点没起点。

class Solution {
public:
    int canCompleteCircuit(vector<int>& gas, vector<int>& cost) {
        if(gas.size()==0)
            return 0;
        vector<int> reserve(gas.size(),0);
        for(int i=0;i<gas.size();i++)
            reserve[i]=gas[i]-cost[i];//从 i 到 i+1 ,从i得到gas[i],消耗cont[i]
        for(int i=0;i<gas.size();i++)
        {
            if(reserve[i]>0)
            {
                int val=0;
                int k=i;
                for(int j=0;j<gas.size();j++)
                {
                    k = (k>=gas.size()) ? k%gas.size() : k;
                    val+=reserve[k];
                    if(val<0)
                        break;
                    k++;
                }
                if(val>=0)
                    return i;
            }
        }
        return -1;
    }
};


其实可以化为求最大连续序列和:求reserve(reserve[i]=gas[i]-cost[i]) 循环数组 的最大连续序列和

class Solution {
public:
    int canCompleteCircuit(vector<int>& gas, vector<int>& cost) {
        if(gas.size()==0)
            return 0;
            
        vector<int> reserve(gas.size(),0);
        for(int i=0;i<gas.size();i++)
            reserve[i]=gas[i]-cost[i];//从 i 到 i+1 ,从i得到gas[i],消耗cont[i]
            
        int start=0;
        int maxVal=0;
        int tmpVal=0;
        int tmpStart=0;
        
        for(int i=0;i-tmpStart<gas.size();i++)
        {
            if(reserve[i%gas.size()]>0)
                tmpVal+=reserve[i%gas.size()];
            else
            {
                maxVal= maxVal<tmpVal? (start=tmpStart,tmpVal):maxVal;
                tmpStart=i%gas.size()+1;
                tmpVal=0;
            }
        }
        cout<<start<<endl;
        int val=0;
        for(int i=start;i-start<gas.size();i++){
            val+=reserve[i%gas.size()];
            if(val<0)
                return -1;
        }
        return start;
    }
};

但是下面的测试 不能通过

[6,1,4,3,5]
[3,8,2,4,2]

因为:
            虽然reserve[i%gas.size()]<0,但是tmpVal+reserve[i%gas.size()]可能还是大于0通过i与i+1的值串起来可能很大,即
            tmpVal+reserve[i%gas.size()] + reserve[(i+i)%gas.size()] 的结果 可能很大
,如 [3,-7,2,-1,3]序列中 2 -1+3+3才是最大的

所以当reserve[i%gas.size()]<0时 不能就这么裁断放弃,从下一个位置重新开始:
                maxVal= maxVal<tmpVal? (start=tmpStart,tmpVal):maxVal;
                tmpStart=i%gas.size()+1;
                tmpVal=0;

而是改成下面这样,只要(tmpVal+reserve[i%gas.size()]) > 0 就继续累计

class Solution {
public:
    int canCompleteCircuit(vector<int>& gas, vector<int>& cost) {
        if(gas.size()==0)
            return 0;
            
        vector<int> reserve(gas.size(),0);
        for(int i=0;i<gas.size();i++)
            reserve[i]=gas[i]-cost[i];//从 i 到 i+1 ,从i得到gas[i],消耗cont[i]
            
        int start=0;
        int maxVal=0;
        int tmpVal=0;
        int tmpStart=0;
        
        for(int i=0;i-tmpStart<gas.size();i++)
        {
            if(reserve[i%gas.size()]>0)
                tmpVal+=reserve[i%gas.size()];
            else
            {
            /*
            不能就这么做
                maxVal= maxVal<tmpVal? (start=tmpStart,tmpVal):maxVal;
                tmpStart=i%gas.size()+1;
                tmpVal=0;
            虽然reserve[i%gas.size()]<0,但是tmpVal+reserve[i%gas.size()]可能大于0,
            tmpVal+reserve[i%gas.size()] + reserve[(i+i)%gas.size()] 的结果 可能很大,如 [3,-7,2,-1,3]序列中 2-1+3+3才是最大的
            */  
                maxVal= maxVal<tmpVal? (start=tmpStart,tmpVal):maxVal;//先记录下,看是不是最大,因为后面可能要加负数了
                if( (tmpVal+reserve[i%gas.size()]) > 0 )
                {
                    tmpVal+=reserve[i%gas.size()];
                    continue;//还可以继续与后面的数据相加看看
                }
                else
                {
                    //tmpVal+reserve[i%gas.size()]小于0,对后面的累计没有正作用,只有副作用,所以舍弃,就从下个位置开始重新判断了
                    tmpStart=i%gas.size()+1;
                    tmpVal=0;
                }
            }
        }
        cout<<start<<endl;
        int val=0;
        for(int i=start;i-start<gas.size();i++){
            val+=reserve[i%gas.size()];
            if(val<0)
                return -1;
        }
        return start;
    }
};


改进:如果所有reserver的元素值加起来等于total < 0,那肯定跑不了,返回-1即可。

循环序列的最大连续序列和=max(非循环序列最大连续序列和,非循环序列total - 非循环序列最小连续序列和)

class Solution {
public:
    int canCompleteCircuit(vector<int>& gas, vector<int>& cost) {
        if(gas.size()==0)
            return 0;
            
        
        int diff;//gas[i]-cont[i]:从 i 到 i+1 ,从i得到gas[i],消耗cont[i]
            
        int startMax=0;
        int maxVal=gas[0]-cost[0];
        
        int tmpStartMax=0;
        int tmpMaxVal=gas[0]-cost[0];
        
        int minVal=gas[0]-cost[0];
        int tmpMinVal=gas[0]-cost[0];
        int endMin=0;
        
        int total=gas[0]-cost[0];
        
        for(int i=1;i<gas.size();i++)
        {
            diff=gas[i]-cost[i];
            total+=diff;
            if(tmpMaxVal<0) //前面的不行,那从这里开始i
            {
                tmpMaxVal=diff;
                tmpStartMax=i;
            }
            else
                tmpMaxVal+=diff;//也许diff小于0,这里tmpMaxVal变小了,但是上次计算tmpMaxVal的时候,已经运行过33行,与maxVal比较了,
            maxVal=maxVal<tmpMaxVal? startMax=tmpStartMax,tmpMaxVal:maxVal;//这一次i的
            
            if(tmpMinVal>0)
                tmpMinVal=diff;//从现在i开始重来,只要记录最小连续序列 的最后一个序列,所以不用存i
            else
                tmpMinVal+=diff;
            minVal=minVal>tmpMinVal?endMin=i,tmpMinVal:minVal;
        }
        return total<0 ? -1 : ( maxVal > (total-minVal) ? startMax : (endMin+1)%gas.size()) ;
    }
};
参考: http://www.cnblogs.com/felixfang/p/3814463.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值