1 题目有一个数组arr, 里面全是正数,给定一个数值K,求出和为K的最长子数组的长度。
如[3,2,1,1,1,6,1,1,1,1,1,1] sum = 6, 最大长度是6.
子数组:一定是连续的,子串也是连续的,子序列才可以不连续。
分析:
首先题目里面数组的数据都是正数,所以SUM和与数组窗口的范围是严格单调递增的,也就是说范围越长,和SUM越大。
假设我们的子数组的范围[l,r],
(1) L, R : SUM < K, 则R++, 即右移 R ->
(2)L, R : SUM > K, 则此时L -> 即L++
(3)L,R : SUM == K, 这时候我们有两种选择,任意一种都可以,
(a) R-> 这时候L,R+1 SUM > K, 则L就会->
(b) L->, 这时候L+1,R SUM一定 < K。 那么R就会->
所以我们可以看到L, R 在找到等于K的子数组范围的时候,都会向右移动(->)
代码如下:
package data.structure.数组累加和;
public class LongestSubArrLength {
public static void main(String[] args) {
int[] arr = new int[]{3,2,1,1,1,6,1,1,1,1,1,1};
LongestSubArrLength longestSubArrLength = new LongestSubArrLength();
int i = longestSubArrLength.longestSubArrLenEQK(arr, 6);
System.out.println("result " + i);
}
private int longestSubArrLenEQK(int[] arr, int K) {
if (arr == null || arr.length == 0 || K <= 0) {
return -1;
}
int L = 0;
int R = 0;
int len = 0; // 记录最长子数组的长度,初始化为0
int windowSum = arr[0]; // 代表[L,R]这个左闭右闭窗口的窗口和
while (true) {
if (windowSum < K) {
if (R+1 >= arr.length) {
break;
} else {
windowSum += arr[++R];
}
} else if (windowSum > K) {
windowSum -= arr[L++];
} else {
len = Math.max(len, R-L+1);
if (R + 1 >= arr.length) {
break;
} else {
windowSum += arr[++R];
}
}
}
return len;
}
}
2 题目有一个数 组arr, 里面是正数,负数,0,给定一个数值K,求出和为K的最长子数组的长度。
假设j 代表以arr[j]为尾巴的和SUM,那么SUM-10 这个和如果之前存在,并且记录了其index位置,那么j - index(SUM-10) 就是找到的一个子数组的长度。
因此我们想到通过Map去存储,Key是SUM和, value就是第一次出现和sum的索引位置(之所以是存储第一次出现的位置,是因为我们尽可能要取最长的那个子数组长度)。
举例[5,6,4,-3,0,3] K = 10
一开始j=0, arr[j] = 5, sum = 5, map[5-10]不存在,所以以5结尾的满足要求的子数组并不存在。记录map[5]=0;
之后j=1, sum=11, map[11-10]不存在,所以以6结尾也找不到符合的,记录map[11]=1
然后j=2, sum=15, map[15-10]=map[5] = 0, 找到了,那么len = max(0, 2-0)) = 2,此事因为map[15]不存在记录map[15]=2;
然后j=3, sum=12, map[12-10]= map[2]不存在,记录map[12] = 3
然后j=4, sum=12, map[12-10]= map[2]不存在,但是map[12]已经存在了,不更新索引,我们要保留最初形成sum和的索引,索引map[12]还是3不变
然后j=5, sum = 15, map[15-10]= map[5]=0,又找到了,此事就开始更新len=max(len,5-0)=5,但是map[15]之前已经存储过了,索引map[15]不更新
之后j已经找完了,此时的len就是我们要的最大值了。
代码如下:
package data.structure.数组累加和;
import java.util.HashMap;
import java.util.Map;
public class LongestSubArrLength2 {
public static void main(String[] args) {
int[] arr = new int[]{5,6,4,-3,0,3};
LongestSubArrLength2 longestSubArrLength = new LongestSubArrLength2();
int i = longestSubArrLength.longestSubArrLenEQK2(arr, 10);
System.out.println("result " + i);
arr = new int[]{3,-3,5,-3,0,3};
i = longestSubArrLength.longestSubArrLenEQK2(arr, 5);
System.out.println("result " + i);
}
private int longestSubArrLenEQK2(int[] arr, int K) {
if (arr == null || arr.length == 0 || K <= 0) {
return -1;
}
Map<Integer, Integer> sumPosMap = new HashMap<>();
// 很重要,我们需要考虑假设要找0的可能性, 如{3,-3,5,-3,0,3}
sumPosMap.put(0,-1);
int sum = 0;
int len = 0;
for (int j = 0; j < arr.length; j++) {
sum += arr[j];
int request =sum - K;
if (sumPosMap.containsKey(request)) {
len = Math.max(len, j - sumPosMap.get(request));
}
if (!sumPosMap.containsKey(sum)) {
sumPosMap.put(sum, j);
}
}
return len;
}
}