Leetcode题集——maximum-subarray

本文介绍了如何解决LeetCode上的最大子数组和问题,通过动态规划法和分治策略来找到数组中连续子序列的最大和。动态规划解决方案的时间复杂度为O(n),而分治策略的时间复杂度为O(nlogn)。文中详细阐述了两种方法的思路,并提供了递归求解的方案。

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

For 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.

click to show more practice.

解析:求一个输入数组的连续子序列的最大和值。

方法一:动态规划法:

时间复杂度为O(n)。

设sum[i]为以第i个元素结尾且和最大的连续子数组。假设对于元素i,所有以它前面的元素结尾的子数组的长度都已经求得,那么以第i个元素结尾且和最大的连续子数组实际上,要么是以第i-1个元素结尾且和最大的连续子数组加上这个元素,要么是只包含第i个元素,即sum[i] = max(sum[i-1] + a[i], a[i])。可以通过判断sum[i-1] + a[i]是否大于a[i]来做选择,而这实际上等价于判断sum[i-1]是否大于0。由于每次运算只需要前一次的结果,因此并不需要像普通的动态规划那样保留之前所有的计算结果,只需要保留上一次的即可,因此算法的时间和空间复杂度都很小。

class Solution {
public:
    bool invalidinput=false;
    int maxSubArray(int A[], int n) 
    {
       if(A==NULL||n<=0)
       {
          invalidinput=true;
           return 0;
       }
        invalidinput=false;
        
        int cursum=0;
        int sum=0x80000000;
        for(int i=0;i<n;i++)
        {
           if(cursum<=0)
               cursum=A[i];
           else
               cursum+=A[i];
            
            if(cursum>sum)
                sum=cursum;
        }
        return sum;
    }
};
方法二、分治方法

也就是递归求解。时间复杂度为O(nlogn)。这是个分治的思想,解决复杂问题我们经常使用的一种思维方法——分而治之。

而对于此题,我们把数组A[1..n]分成两个相等大小的块:A[1..n/2]和A[n/2+1..n],最大的子数组只可能出现在三种情况:
    A[1..n]的最大子数组和A[1..n/2]最大子数组相同;
    A[1..n]的最大子数组和A[n/2+1..n]最大子数组相同;
    A[1..n]的最大子数组跨过A[1..n/2]和A[n/2+1..n]
前两种情况的求法和整体的求法是一样的,因此递归求得。
第三种,我们可以采取的方法也比较简单,沿着第n/2向左搜索,直到左边界,找到最大的和maxleft,以及沿着第n/2+1向右搜索找到最大和maxright,那么总的最大和就是maxleft+maxright。因为要跨过中间点,因此返回必须为maxleft和maxright之和!
而数组A的最大子数组和就是这三种情况中最大的一个。

int find_max_crossing(int arr[],int low,int mid,int high,int *left,int *right)
{
  int lsum=-100;
  int sum=0;
  
  for(int i=mid;i>=low;--i)
  {
    sum+=arr[i];
	if(sum>lsum)
	{
	  lsum=sum;
	   *left=i;
	}
  }
  
  int rsum=-100;
    sum=0;
  for(int j=mid+1;j<=high;j++)
  { 
    sum+=arr[j];
	if(sum>rsum)
	{
	  rsum=sum;
	  *right=j;
	}
  }
  return rsum+lsum;
}
int max_sum_array(int arr[],int low,int high,int *left,int *right)
{
   if(low==high)
   {//递归结束点
     *left=low;
	 *right=high;
	 return arr[low];
   }
   
   int mid=(low+high)/2;
   int lleft,lright,rleft,rright,mleft,mright;
   
   //三种情况下分别求解
   int lmax=max_sum_array(arr,low,mid,&lleft,&lright);
   int rmax=max_sum_array(arr,mid+1,high,&rleft,&rright);
   int mmax=find_max_crossing(arr,low,mid,high,&mleft,&mright);
   //返回最大值
   if(lmax>rmax&&lmax>mmax)
   {
     *left=lleft;
	 *right=lright;
	 return lmax;
   }
   if(rmax>lmax&&rmax>mmax)
   {
     *left=rleft;
	 *right=rright;
	 return rmax;
   }
   if(mmax>lmax&&mmax>rmax)
   {
     *left=mleft;
	 *right=mright;
	 return mmax;
   }  
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值