子数组累加和问题

给定一个整数数组(无序且有正有负)和一个目标值,求这个数组中子数组的和为目标值的子数组的最大长度。
求解思路:子数组是连续的,s[i]表示从0~i位置的累加和,s[j]表示0~j位置的累加和,那么从j+1~i位置的累加和为s[j]-s[i],他可以表示任意子数组的累加和,如果这个累加和就是目标值aim,那么找出长度最长的即可。
遍历一遍数组,并求出各个位置的累加和,如在i位置时求得为s[i],在此我们是否可以得到在0-i之间的所有子数组中是否存在累加和为aim的,只需要查询下s[i]-aim 这个值是否在之前计算累加和的过程中出现过,具体代码如下:

/**
     * @param arr
     * @param aim
     * @return 
     * 给定一个全是正数的数组arr, 和一个整数aim, 求累加和为aim的最大子数组长度
     * 基础:子数组是数组中连续的n个元素
     */
    public static int getMaxLength(int[] arr ,int aim){
        if(arr==null||arr.length==0)
            return 0;
        int sum=0;
        int len=0;
        //sum记录从0到i位置处的连续累加和,哈希表记录以value下标结尾从0开始的累加和key
        HashMap<Integer,Integer> map=new HashMap<Integer, Integer>();
        //sum [0----i]  aim  [j+1-----i] sum-aim [0---j]  要求的数从j+1开始,当j+1=0时,即从开头开始,j=-1;
        //不加任何一个数时,累加和为0,此时下标为-1,就表示还没有添加任何数
        map.put(0, -1);
        for(int i=0;i<arr.length;i++){
            sum+=arr[i];
            if(map.containsKey(sum-aim)){//判断哈希表中现在是否存在sum-aim,如果存在得到他的下标j,那么从j+1到i就是子数组和为aim
                //记录的下标应该为最早出现的j 后面再出现不更新  i-j最大
                len=Math.max(i-map.get(sum-aim), len);
            }
            //在后续遍历过程中如果出现了相同的sum,不更新
            if(!map.containsKey(sum))//该处的sum值是第一次出现,后面再出现的话不更新
                map.put(sum, i);
        }
        return len;
    }

如果给定的数组全是正整数,能不能不用额外的空间。双指针实现,left、right两个指针之间的窗口的累加和,如果小于aim ,right++ 并且sum加上新元素,超过了,left ++ 并把之前的数组从sum中去除,记录等于aim的值。

public static int getPosLen(int[] arr, int aim){
        if(arr==null||arr.length==0||aim<0)
            return 0;
        int sum=arr[0];
        int len=0;
        int left=0;
        int right=0; //sum 为left -right 之间的数之和
        for(int i=0;i<arr.length;i++){
            if(sum==aim){
                len=Math.max(len, right-left+1);
                sum-=arr[left++];
            }
            else if(sum<aim){
                right++;
                if(right==arr.length)
                    break;
                sum+=arr[right];
            }
            else{
                sum-=arr[left++];
            }
        }
        return len;
    }
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值