赞
踩
题目描述:
有i个加油站
gas[i]代表在第i个加油站可以加到的油
cost[i]代表从第i个加油站到第i+1个加油站消耗的油
题目想问,从下标为几的节点出发,可以完美的绕一圈回到该节点,细节在题目的explanation也有讲。
解析:
这道题先用贪心算法试试,那就必须要提出贪心策略。
凡事都从最简单的思路开始,首先先提出一个思路:每个站点都会加油再耗油,那么会有一个实际的值:实际值 = 加油量 - 耗油量
比如我们的实例:
gas = [1,2,3,4,5] cost = [3,4,5,1,2]
实际值 = [-2,-2,-2,3,3]
首先先把特殊情况不能成环给排除:如果所有的实际值加起来<0,那无论怎么走都成不了环,因为耗油总量 > 加油总量
再来看能成环时取哪个节点,一开始想出一个思路:取实际值最大那个点,但马上举了个反例推翻了自己 [ 1 2 3 4 -1 7 -8 ],7最大,但是1 2 3 4比7还大,那7只是看起来最大,我们还是要找那个最大的,于是就改进了思路:以负数为分割,比如这个例子,以负数为分割的结果为: [ 1 2 3 4 ]、[ 7 ],我们取每个部分相加后最大,[ 1+2+3+4 = 10 ] > [ 7 ],那么最终输出节点是index:0
从这个例子看我们的思路是没问题,那么看看能不能在举出反例,想出了这种反例[ 7 -8 2 -1 ],我们之前的策略是贪心的找最大的正数,但是很有可能这个正数后跟一个很大的负数,所以至少保证我们找的那个正数在能到达下一跳正数的情况下最大。
贪心思路:我们找的那个正数在能到达下一跳正数的情况下最大。
也就是例子:[ 1 2 3 4 -1 7 -8 ] = > [ 1 2 3 4 -1 ]、[ 7 -8 ] = > [ 9 ] > [ -1 ](所以取前面那一段的第一个元素下标)
[ 7 -8 2 -1 ] = > [ 7 -8 ]、[ 2 -1 ] = > [ -1 ] < [ 1 ](所以取后面那一段的第一个元素下标)
代码:
- class Solution {
- public:
- int canCompleteCircuit(vector<int>& gas, vector<int>& cost) {
- //记录每个几点加完油消耗完情况
- vector<int> addAndCost;
- //把每个点是油大于消耗还是消耗大于油记录下来
- int tmp;
- for(int i = 0; i < gas.size(); i++){
- tmp = gas[i] - cost[i];
- addAndCost.push_back(tmp);
- }
- //记录起始index
- int startIndex = 0;
- int tmpIndex = -1;
- //连续的最大值,如下策略
- //[ 1 2 3 4 -1 7 -8 ] = > [ 1 2 3 4 -1 ]、[ 7 -8 ] = > [ 9 ] > [ -1 ]
- int tmpMax = 0;
- int tmpScore = 0;
- //sum,统计一下,如果所有的和小于0说明不能环
- int sum = 0;
- int times = 0;
- int i;
- //第二圈的时候,遇到第一个负数,后面再遇到正数停下
- int flag = 0;
- for(int j = 0; j < 2 * addAndCost.size(); j++){
- i = j % addAndCost.size();
- if(j >= addAndCost.size() && addAndCost[i] < 0) flag = 1;
- if(addAndCost[i] >= 0) {
- //第一个下标,比如1, 2, 3, 4取1
- if(tmpIndex == -1) tmpIndex = i;
- //例如 1 1 -1 -2 1,我要记录的下标是0,我要相加的是(1+1+(-1)+(-2)),负数时会设置times为1,下一次正数进行比对
- if(times == 1){
- //更新最大
- if(tmpScore > tmpMax){
- tmpMax = tmpScore;
- startIndex = tmpIndex;
- }
- tmpScore = 0;
- tmpIndex = i;
- times = 0;
- }
- //第二圈的时候,遇到第一个负数,后面再遇到正数停下
- if(flag == 1 && addAndCost[i] >= 0) break;
- tmpScore += addAndCost[i];
- }else{
- tmpScore += addAndCost[i];
- times = 1;
- }
- //用于计算是否能成环
- if(j < addAndCost.size()) sum += addAndCost[i];
- }
- //为了正数一直连续到最后的情况,需要加个判断
- if(tmpScore >= tmpMax){
- tmpMax = tmpScore;
- startIndex = tmpIndex;
- }
- if(sum < 0) return -1;
- else return startIndex;
- }
- };
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。