LeetCode: Gas Station


之前找别人的解体方案的时候总是习惯性的找有文字描述的,今天看到这个Gas Station的题目,文字说明到让我有点糊涂,代码加公式的描述竟然更好理解。

这篇博客里面说Gas Station的问题其实是最大子段和 ,只不过是一个循环的。然后就Google了一下最大子段和的求法,发现这个最大子段和详解(N种解法汇总) 里面描述了各种解法,非常好。不过其中分治发和动态规划发的文字描述虽然很详细却并不好理解,而这篇 文章里面几个公式加代码让我一下就看懂了。具体就是:

问题:

给定n个整数(可能为负数)组成的序列a1,a2,a3,…,a[n],求该序列如a[i]+a[i+1]+…+a[j]的子段和的最大值。当所给的整均为负数时定义子段和为0,依此定义,所求的最优值为: Max{0,a[i]+a[i+1]+…+a[j]},1<=i<=j<=n 例如,当(a1,a2,a3,a4,a4,a6)=(-2,11,-4,13,-5,-2)时,最大子段和为20。

分治法:

将a[1n]分成a[1n/2]和a[n/2+1n],则a[1n]的最大字段和有三种情况: (1)a[1n]的最大子段和与a[1n/2]的最大子段和相同 (2)a[1n]的最大子段和与a[n/2n]的最大子段和相同 (3)a[1n]的最大子段和为ai++aj,1<=i<=n/2,n/2+1<=j<=n T(n)=2T(n/2)+O(n) T(n)=O(nlogn)

int MaxSum_DIV(int *v,int l,int r)
{
int k,sum=0;
if(l==r)
    return v[l]>=0?v[l]:0;
else
{
    int center=(l+r)/2;
    int lsum=MaxSum_DIV(v,l,center);
    int rsum=MaxSum_DIV(v,center+1,r);

    int s1=0;
    int lefts=0;
    for (k=center;k>=l;k--)
    {
        lefts+=v[k];
        if(lefts>s1)
            s1=lefts;
    }

    int s2=0;
    int rights=0;
    for (k=center+1;k<=r;k++)
    {
        rights+=v[k];
        if(rights>s2)
            s2=rights;
    }
    sum=s1+s2;
    if(sum<lsum)
        sum=lsum;
    if(sum<rsum)
        sum=rsum;
}
return sum;
}

动态规划法:

b[j]=max{a[i]+…+a[j]},1<=i<=j,且1<=j<=n,则所求的最大子段和为max b[j],1<=j<=n。 由b[j]的定义可易知,当b[j-1]>0时b[j]=b[j-1]+a[j],否则b[j]=a[j]。故b[j]的动态规划递归式为: b[j]=max(b[j-1]+a[j],a[j]),1<=j<=n。 T(n)=O(n)

int MaxSum_DYN(int *v,int n)
{
int sum=0,b=0;
int i;
for (i=1;i<=n;i++)
{
    if(b>0)
        b+=v[i];
    else
        b=v[i];
    if(b>sum)
        sum=b;
}
return sum;
}

这个题要用反证法来理解。算法:

代码:

public class Solution {
    public int canCompleteCircuit(int[] gas, int[] cost) {
        // Note: The Solution object is instantiated only once and is reused by each test case.
        int N = gas.length, startIndex = -1;//为什么是-1 ?
        int sum = 0, total = 0;
        for(int i = 0; i < N; i++){
            sum += (gas[i] - cost[i]);
            total += (gas[i] - cost[i]);
            if(sum < 0){
                startIndex = i; 
                sum = 0;
            }
        }
        return total >= 0 ? startIndex + 1 : -1;
    }
}

Haiyang Xu 21 April 2014