leetcode-加油站之贪心算法和最小子序和

题目在这里插入图片描述

思路1

第一想法是用贪心算法,我先不管我到底能不能跑到终点,只有油够我去下一站我就跑,不够就不跑,换下一站作为起点跑;那么需要两个循环,时间复杂度应该是O(n^2):

class Solution {
public:
    int canCompleteCircuit(vector<int>& gas, vector<int>& cost) {
        int remain = 0;
        for(int i=0;i<cost.size();i++)
        {
            remain = gas[i];
            int j = i;
            int flag = 0;
            while(remain - cost[j]>=0)
            {
                remain = remain - cost[j];
                j = (j+1)%cost.size();
                remain +=gas[j];
                flag=1;
                if(j==i)
                break;
            }
            if(flag == 1&&j ==i )
            return i;
        }
        return -1;

    }
};

但是这种简单粗暴的做法效率很低:
在这里插入图片描述

思路2

在题解看到有人说,思路其实和另外一题:最小子序和的思路一样;那一题我是做过的,也很巧妙:
在这里插入图片描述思路是:
若一个子序的起点为负数,那么这个子序之和必定无法取得最大;同理,若在一个子序列中开头的若干连续数字之和为负数,那么也必定无法取得最大;
从这个理论出发,我们可以认为:一个具有最大和的连续子数组res[n],前k(k<=n)个连续数字之和不小于0;

简单的说就比如:
-2是负数,肯定不能拿它作为开头,去到下一位1
1是正数,尝试着拿它作为序列开头,sum=0+1,去到下一位-3
sum=1-3=-2是负数,那肯定不能拿它作为开头,去到下一位4
…以此类推
代码:

class Solution {
public:
    int maxSubArray(vector<int>& nums) {
        int sum = nums[0];
        int res=sum;
        for(int i=1;i<nums.size();i++)
        {
            if(sum<0)
            //要是sum是负数,那么应该换下一个作为序列的开头
            sum = nums[i];
            else
            sum += nums[i];

            res = max(sum,res);
        }
        return res;
    }
};

这么看就发现可以用最小子序和的思想了做这道题了;我们可以先将gas和cost做差得到一个数列,这个数列的每一个元素就是车子经过要变动的油耗,这整个数列的和要是大于等于0,那么车子就有可能能跑一个环,具体就要看从哪个位置开始跑;
举例:
-2,+3,-2,-2,+3
也和最小子序和一样,要是开头经过的几个油站为负数,那么肯定跑不过去,那么可以把数列分为两部分,前面的部分和是负数,后面部分的和是正数;找到这个后面部分的起点,就是要的结果;这样一次遍历就可以了,时间复杂度在O(n);

代码:

class Solution {
public:
    int canCompleteCircuit(vector<int>& gas, vector<int>& cost) {
        vector<int> minus;
        int sum = 0;
        for(int i=0;i<gas.size();i++)
        {
            minus.push_back(gas[i]-cost[i]);
            sum = sum + gas[i] - cost[i];
        }
        if(sum<0)
        //要是总和为负数的话,那肯定跑不了一环
        return -1;
        int tmp = minus[0];
        int start = 0;
        for(int i=1;i<minus.size();i++)
        {

            if(tmp<0)
            {
                tmp = minus[i];
                start = i;
            }
            else
            tmp+=minus[i];
        }
        return start;


    }
};

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值