数组三连问题

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         }

猜你喜欢

转载自www.cnblogs.com/liujunj/p/10423796.html