【Leetcode】53. Maximum Subarray

来源:互联网 发布:网红美妆淘宝店前十名 编辑:程序博客网 时间:2024/05/29 08:45

Description:

Find the contiguous subarray within an array (containing at least one number) which has the largest sum.

Example:

Given the array [-2,1,-3,4,-1,2,1,-5,4],
the contiguous subarray [4,-1,2,1] has the largest sum = 6.


思路:

此题有多种解题思路。常规的解题方式,可以通过循环逐个比较连续的子数组(或者叫子序列)内元素的和的大小,以下是C++的实现方式

class Solution{    public:    int MaxSubArray(int *arr,int len,int left, int right){        int temp = 0;        int max = 0;        for(i=0;i<len;i++){            temp = 0;            for(j=i;j<len;j++){                temp += arr[j];                if(temp>max){                    max = temp;                    left = i;                    right = j;                }            }        }        return max;     }    private:    int i,j,len;    int *arr;    int left,right;//数组的左右两端起末位置};

但是这种方法的时间复杂度为O(n^2),对于数组元素个数较多的时候,效率会比较低。

我们可以仔细观察得到,循环比较逐个比较把所有可能的子序列都计算了一遍,但实际上不需要计算所有的子序列,如果有些子序列的开头和结尾是负数的话是无法得到和的最大值,因此可以只计算开头和结尾为正数的。更具体来说,开头是正数可以转换为这样一个问题:上一个元素的值a[i-1]与当前元素的值a[i]的和比当前元素的值a[i]要小,那么取当前元素的位置作为最大子序列的起始位置,否则保持不变。同样的,结尾为正数可以转化为:当前元素的值a[i]和下一个元素的值a[i+1]比当前元素大,那么下一个元素的位置作为最大子序列的结束位置,否则保持不变。这样,我们得到了一个递归的解决方式。

class Solution {    public:    int MaxSubArray(int *arr,int len){        int max_sum = arr[0];        int max_end_pos = arr[0];        int sum = 0;        left = 0;        right = 0;        for(int i=1;i<len;i++){            sum = max_end_pos + arr[i];            if(sum > arr[i]){                max_end_pos = sum;            }else{                max_end_pos = arr[i];                left = i;            }            if(max_sum<max_end_pos){                max_sum = max_end_pos;                right = i;            }         }        return max_sum;    }    private:    int i,j,len;    int *arr;    int left,right;};

由此可见,该算法中只有一次循环,算法复杂度为O(n),拥有十分优异的效率。

除此之外,该问题还可以用分治法来解答。用分治法的时间复杂度为O(nlogn),比常规算法效率高。

class Solution{    public:    int MaxInThree(int a,int b,int c){        if(a>b) a = b;        if(a<c)             return c;        else             return a;    }     int MaxSubArray(int *arr,int left,int right){        int max_left_sum,max_right_sum;//左右两半部分最大的和        int sub_left_sum=0,sub_right_sum=0; //左子序列的和与右子序列的和        int max_sub_left_sum=0,max_sub_right_sum=0;//左子序列的最大和与右子序列的最大和        int mid;        //当只有一个元素的时候         if(left==right){            if(a[left]>0)                 return a[left]            else                 return 0;        }        //将数组分为两部分,分别求两部分的和的最大值        mid=(left+right)/2;        max_left_sum = MaxSubArray(arr,left,mid);        max_right_sum = MaxSubArray(arr,mid+1,right);        //在左半部分从中间到左侧进行子序列匹配        for(i=mid;i>=left;i--){            sub_left_sum+=arr[i];            if(sub_left_sum>max_sub_left_sum)                max_sub_left_sum = sub_left_sum;        }        //在右半部分从中间到右侧进行子序列匹配        for(i=mid+1;i<=right;i++){            sub_right_sum+=arr[i];            if(sub_right_sum>max_sub_right_sum)                max_sub_right_sum = sub_right_sum;        }        return MaxInThree(max_left_sum,max_right_sum,max_sub_left_sum+max_sub_right_sum);    }    private:    int i,j,len;    int *arr;    int left,right;};
0 0
原创粉丝点击