当前位置:   article > 正文

LeetCode 134. Gas Station (贪心)

leetcode 134. gas station

题目描述:

有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 ](所以取后面那一段的第一个元素下标)

 

代码:

  1. class Solution {
  2. public:
  3. int canCompleteCircuit(vector<int>& gas, vector<int>& cost) {
  4. //记录每个几点加完油消耗完情况
  5. vector<int> addAndCost;
  6. //把每个点是油大于消耗还是消耗大于油记录下来
  7. int tmp;
  8. for(int i = 0; i < gas.size(); i++){
  9. tmp = gas[i] - cost[i];
  10. addAndCost.push_back(tmp);
  11. }
  12. //记录起始index
  13. int startIndex = 0;
  14. int tmpIndex = -1;
  15. //连续的最大值,如下策略
  16. //[ 1 2 3 4 -1 7 -8 ]  = > [ 1 2 3 4 -1 ]、[ 7 -8 ]  = >  [ 9 ] > [ -1 ]
  17. int tmpMax = 0;
  18. int tmpScore = 0;
  19. //sum,统计一下,如果所有的和小于0说明不能环
  20. int sum = 0;
  21. int times = 0;
  22. int i;
  23. //第二圈的时候,遇到第一个负数,后面再遇到正数停下
  24. int flag = 0;
  25. for(int j = 0; j < 2 * addAndCost.size(); j++){
  26. i = j % addAndCost.size();
  27. if(j >= addAndCost.size() && addAndCost[i] < 0) flag = 1;
  28. if(addAndCost[i] >= 0) {
  29. //第一个下标,比如1, 2, 3, 4取1
  30. if(tmpIndex == -1) tmpIndex = i;
  31. //例如 1 1 -1 -2 1,我要记录的下标是0,我要相加的是(1+1+(-1)+(-2)),负数时会设置times为1,下一次正数进行比对
  32. if(times == 1){
  33. //更新最大
  34. if(tmpScore > tmpMax){
  35. tmpMax = tmpScore;
  36. startIndex = tmpIndex;
  37. }
  38. tmpScore = 0;
  39. tmpIndex = i;
  40. times = 0;
  41. }
  42. //第二圈的时候,遇到第一个负数,后面再遇到正数停下
  43. if(flag == 1 && addAndCost[i] >= 0) break;
  44. tmpScore += addAndCost[i];
  45. }else{
  46. tmpScore += addAndCost[i];
  47. times = 1;
  48. }
  49. //用于计算是否能成环
  50. if(j < addAndCost.size()) sum += addAndCost[i];
  51. }
  52. //为了正数一直连续到最后的情况,需要加个判断
  53. if(tmpScore >= tmpMax){
  54. tmpMax = tmpScore;
  55. startIndex = tmpIndex;
  56. }
  57. if(sum < 0) return -1;
  58. else return startIndex;
  59. }
  60. };

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Cpp五条/article/detail/493492
推荐阅读
相关标签
  

闽ICP备14008679号