题解 | #未排序数组中累加和为给定值的最长子数组长度#
未排序数组中累加和为给定值的最长子数组长度
http://www.nowcoder.com/practice/704c8388a82e42e58b7f5751ec943a11
未排序数组中累加和为给定值的最长子数组长度
问题描述:给定一个无序数组arr, 其中元素可正、可负、可0。给定一个整数k,求arr所有子数组中累加和为k的最长子数组长度
示例
输入:[1,-2,1,1,1],0
返回值:3
说明:最长子数组为[1,-2,1],其长度为3
方法一
思路分析
本题我们能直接想到的办法就是暴力穷举,外层循环从数组开始位置遍历,内层循环遍历从上一层的位置开始,使用sum记录当前数组的和,如果达到k,将数组长度记录下来,之后继续向后遍历,当内层循环遍历到数组结束位置后,外层循环往下继续刚才的操作。这种方法时间复杂度较大。因此我们考虑使用前缀和数组,定义数组$pre[i]=arr[0]+arr[1]+...+arr[i-1]$,那么子数组$arr[i]$到$arr[j-1]$的和为$pre[j]-pre[i]$而后计算出所有可能的前缀和数组,特别的数组中第一个元素的前缀和初始化为0,接着我们根据子数组的可能的长度,按长度的最大值开始向下遍历,即按照数组长度由大到小找到原数组中可能的子数组,如果子数组的和$pre[j]-pre[i]$为k,则输出当前的子数组长度。
图解
输入:[1,-2,1,1,1],0
首先计算其前缀数组$pre[6]=\{0,1,-1,0,1,2\}$
| $len$ | 子数组的起止位置$i$ | 子数组的和 |
| 5 | 0 | $presum[0+5]-presum[0]=2$ |
| 4 | 0 | $presum[0+4]-presum[0]=1$ |
| 1 | $presum[1+4]-presum[1]=1$ | |
| 3 | 0 | $presum[0+3]-presum[0]=0$ $k=0$程序在此处运行结束 |
| 1 | | |
| 2 | |
JAVA核心代码
import java.util.*;
public class Solution {
/**
* max length of the subarray sum = k
* @param arr int整型一维数组 the array
* @param k int整型 target
* @return int整型
*/
public int maxlenEqualK (int[] arr, int k) {
int n=arr.length;
int[] presum=new int[n+1];
for(int i=0;i<n;i++){
presum[i+1]=presum[i]+arr[i];////构建前缀和数组,开始元素的前缀和为0,因此设置n+1个长度
}
//逆序遍历所有可能的长度
for(int len=n;len>=1;len--)
{
for(int i=0;i+len<=n;i++)
{
if(presum[i+len]-presum[i]==k)//长度为len的子数组的和
{
return len;
}
}
}
return 0;
}
} 复杂度分析
- 时间复杂度:两层的循环,外层循环遍历$n$,内存循环遍历$n-len$,因此时间复杂度为$O(n^2)$
- 空间复杂度: 借助于一个前缀数组,因此空间复杂度为$O(n)$
方法二
思路分析
本题也可采用哈希表的办法,将当前数组arr[0,i]的和做为关键字,i做为值记录在哈希表hashmap中,循环遍历数组,从开始位置出发,记录前缀数组的和presum,如果这个值不在哈希表中,则将其记录在哈希表中,继续判断presum-k是否在哈希表中,如果也在哈希表中,那么i-hashmap[presum-k]这一数值就可作为累加和为k的数组长度,但不一定是最长的,需要继续进行遍历,直到遍历完成。特别的由于数组中可能存在0,而子数组增加0,数组的和不变,长度会增加,因此初始hashmap[0]=-1,以避免以0开始的子数组的计算。
图解
输入:$[1,-2,1,1,1]$,$0$
初始化$hashmap[0]=-1$,$length$初始化为0
| $i$ | $presum +=arr[i]$ | $hashmap$ | $length$ |
| $0$ | $1$ | $hashmap[1]=0$ | $0$ |
| $1$ | $1+(-2)=-1$ | $hashmap[-1]=1$ | $0$ |
| $2$ | $-1+1=0$ | ---------- | $max(length,i-hashmap[presum-k])=max(0,3)=3$ |
| $3$ | $0+1=1$ | ---------- | $max(length,i-hashmap[presum-k])=max(3,3)=3$ |
| $4$ | $1+1=2$ | $hashmap[2]=4$ | $max(length,i-hashmap[presum-k])=max(3,0)=3$ |
python核心代码
#
# max length of the subarray sum = k
# @param arr int整型一维数组 the array
# @param k int整型 target
# @return int整型
#
class Solution:
def maxlenEqualK(self , arr , k ):
# write code here
if arr == None&nbs***bsp;len(arr) == 0:
return 0
hashmap = {}#构建哈希表
hashmap[0] = -1#防止数组中有0的情况,数组中增加0,数组的和不变,数组长度+1
presum = 0
length = 0
for i in range(len(arr)):
presum += arr[i]#构建前缀数组和
if presum not in hashmap:#哈希表中为存放当前值
hashmap[presum]=i
if (presum - k) in hashmap:#presum-k的值在哈希表中,其长度也是最长的,因此可以直接计算总的长度
length = max(length,i-hashmap[presum-k])
return length 复杂度分析
- 时间复杂度:遍历一次数组,因此时间复杂度为$O(n)$
- 空间复杂度: 借助于一个presum变量以及一个哈希数组,因此空间复杂度为$O(n)$
查看12道真题和解析
