未排序数组中累加和为给定值的最长子数组长度

题目:给定一个数组arr,该数组无序,但每个值均为正数,再给定一个正数k。求arr得所有子数组中所有元素相加和为k的最长子数组长度。

解答:最优解可以做到时间复杂度为o(n),额外空间复杂度为o(1).首先用两个位置来标记子数组的左右两头,记为left和right,开始时都在数组的最左边(left=0,right=0)。整体过程如下:

1.开始时变量left=0,right=0,代表子数组arr[left......right].

2.变量sum始终表示子数组arr[left......right]的和。开始时,sum=arr[0],即arr[0....0]的和。

3.变量len一直记录累加和为k的所有子数组中最大子数组的长度。开始时,len=0.

4.根据sum与k的比较结果决定是left移动还是right移动,具体如下:

(1)如果sum==k,说明arr[left.....right]累加和为k,如果arr[left.....right]长度大于len,则跟新len,此时因为数组所有的值都为正数,那么所有从left位置开始,在right之后的位置结束的子数组,累加和一定大于k。所以,令left加1,这表示我们开始考察以left之后的位置开始的子数组,同时令sum=sum-arr[left],sum此时表示arr[left+1.....right]

(2)如果sum小于k,说明arr[left.....right]还需要加上right后面的值,其和才可能达到k,所以,令right+1,sum+=arr[right].需要注意的是,right+1后是否越界。

(3)如果sum大于k,说明所有从left位置开始,在right之后的位置结束的子数组,累计和一定大于k,因此,我们考查以left之后的位置开始的子数组,同时令sum-=arr[left],sum此时表示arr[left+1....right]的累计和。

5.如果right<arr.length,重复步骤4.否则直接返回len,全部过程结束。

具体的参考代码如下:

 1 public  int  getMaxLength(int[] arr,int k)
 2 {
 3     if(arr==null || arr.length==0 || k<=0)
 4                   return 0;
 5     int left=0;
 6     int right=0;
 7     int sum=arr[0];
 8     int len=0;
 9     while(right<arr.length)
10    {
11        if(sum==k)
12      {
13         len=Math.max(len,right-left+1);
14         sum-=arr[left++];
15      }else if(sum<k)
16      {
17          right++;
18          if(right==arr.length)
19                break;
20         sum+=arr[right];
21     }
22    else
23        sum-=arr[left++];
24    }
25 
26   return len;
27 }
View Code

 

posted @ 2016-08-14 22:48  hi,daring  阅读(354)  评论(0编辑  收藏  举报