数据累加和

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;

    }

}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值