1、数组一连 无序数组只有正数,求子数组和等于k的最长子数组长度
解题思想:滑动窗口
两个指针 left 和 right,sum 为 [left....right] 的和。如果 sum < k ,right 右移;如果 sum > k ,left 右移;如果sum == k,left右移或者right右移
代码如下:
1 public static int solution(int [] arr, int k){ 2 if (arr == null || arr.length == 0 || k <= 0) { 3 return 0; 4 } 5 int left = 0; 6 int right = 0; 7 int sum = arr[0]; 8 int len = 0; 9 while (right < arr.length) { 10 if (sum == k) { 11 len = Math.max(len, right - left + 1); 12 sum -= arr[left++]; 13 } else if (sum < k) { 14 right++; 15 if (right == arr.length) { 16 break; 17 } 18 sum += arr[right]; 19 } else { 20 sum -= arr[left++]; 21 } 22 } 23 return len; 24 }
2、数组二连 无序数组有正 负 0,求子数组和等于k的最长子数组长度
解题思想:前缀和(
即如果[i...j...k]中和为sum,如果[i...j]和为s1,那么(j...k]和必为 sum - s1)
代码如下:
1 public static int solution(int [] arr, int k){ 2 if (arr == null || arr.length == 0 || k <= 0) { 3 return 0; 4 } 5 HashMap<Integer,Integer> map = new HashMap<>(); 6 map.put(0,-1); 7 int sum = 0; 8 int len = 0; 9 for(int i = 0; i < arr.length; i++){ 10 sum += arr[i]; 11 if(map.containsKey(sum - k)){ 12 len = Math.max(len,i - map.get(sum - k)); 13 } 14 if(!map.containsKey(sum)){ 15 map.put(sum,i); 16 } 17 } 18 return len; 19 }
3、数组三连 无序数组有正 负 0,求子数组和小于等于k的最长子数组长度
解题思路:预处理数组+滑动窗口
代码如下:
1 public static int solution(int [] arr, int k){ 2 if(arr == null || arr.length == 0){ 3 return 0; 4 } 5 int[] minSums = new int[arr.length]; 6 int[] minSumsEnds = new int[arr.length]; 7 //minSums[i] 代表 i 到arr.length 中最小子数组和 8 minSums[arr.length - 1] = arr[arr.length - 1]; 9 //minSumsEnds[i] 代表 i 到arr.length 中最小子数组和的子数组右边界 10 minSumsEnds[arr.length - 1] = arr.length - 1; 11 //生成预处理数组 12 for(int i = arr.length - 2; i >= 0; i--){ 13 if(minSums[i+1] < 0){ 14 minSums[i] = arr[i] + minSums[i+1]; 15 minSumsEnds[i] = minSumsEnds[i+1]; 16 }else{ 17 minSums[i] = arr[i]; 18 minSumsEnds[i] = i; 19 } 20 } 21 int end = 0; 22 int sum = 0; 23 int res = 0; 24 //i是窗口的最左的位置,end是窗口最右位置的下一个位置 25 for(int i = 0; i < arr.length; i++){ 26 //while循环结束后 27 // 1 如果以i为开头的情况下,累加和<=k 的最长子数组是arr[i...end-1],看看这个长度能不能更新res 28 // 2 如果以i为开头的情况下,累加和<=k 的最长子数组比arr[i...end-1]短,更新还是不更新res都不会影响最终结果; 29 while(end < arr.length && sum + minSums[end] <= k){ 30 sum += minSums[end]; 31 end = minSumsEnds[end]+1; 32 } 33 res = Math.max(res,end - i);//更新res值 34 if(end > i){//窗口还有数 35 sum -= arr[i]; 36 }else{//窗口内已经没数了,表示从i开头的所有子数组累加和都不可能<=k 37 end = i + 1; 38 } 39 } 40 return res; 41 }