笔试面试算法经典-未排序正整数数组中累加和为给定值的子数组

47 篇文章 37 订阅
8 篇文章 1 订阅

【题目】
给定一个数组 arr,该数组无序,但每个数均为正数,再给定一个正数 k 。求 arr 的所有子数组中所有元素相加为k的最长子数组长度。例如,arr=[1,2,1,1,1],k=3。累加和为3的子数组为[1,2] ,[2,3], [1,1,1]。


解法1(时间复杂度O(N)空间复杂度O(1))

思路:left,right来指向数组中的某一个区间,sum用来保存left和right区间中的值,由于数组中的元素都为正数,当right向右移动的时候,sum的值增加,left向右移动时,区间变小sum的值减小。因此可以通过改变left,right的值来遍历数组的所有子区间。

例如上面数组中:刚开始时left=0,right=0,sum=arr[right]=1,此时sum<3,此时移动right=1,sum+=arr[right]=3,所有子数组[1,2]的值符合,此时left向左移动,sum-=arr[left]=2,sum<3,right++,指向1,此时sum+=arr[right]=3,子数组[1,2]符合。重复操作直到right到达数组尾,就可以得到所有值为3的子数组。

public static void longestsumofk1(int arr[],int k)
    {
        if(arr==null||arr.length==0)
            return;
        int left=0,right=0;
        int sum=arr[0];
    //初始时将sum赋值为arr[right].
        while(right<arr.length)
        {
            if(sum==k)
            {   
            //如果sum==k打印left-right之间的子数组    sum是区间left-right元素的和    
                for(int i=left;i<=right;i++)
                    System.out.print(arr[i]+" ");
                System.out.println();
                sum-=arr[left];
                left++;
                //向右压缩区间sum的值减小。
            }
            else if(sum<k)
            {
                right++;
                if(right==arr.length)
                    break;
                sum+=arr[right];
                //如果sum的值<k向右扩展区间,使得sum值增大
            }
            else {
            //否则利用left向右压缩区间。sum值减小。
                sum-=arr[left];
                left++;
            }
        }
    }

解法2(时间复杂度O(n),空间复杂度O(n))

利用性质:sum[i…k] = arr[i]+arr[i+1]….+arr[j]+arr[j+1]+…arr[k] , sum[i…j] = arr[i]+arr[i+1]+…arr[j],如果sum[i…k] – sum[i…j] = result(result为给定的值),那么可知:arr[j+1]+arr[j+2]+…arr[k]=result,因此可以利用上面的性质来遍历数组用 sum来保存遍历过的的数组的所有元素的和,如果hashmap中没有sum值以及当前的数组下标作为(key,value)存放到hashmap中,查看hashmap中是否有sum-k的值存在,如果存在获取其value值,则可知区间[value , j]为符合条件的子数组区间(j为当前数组下标)。

public static void longestsumofk(int arr[],int k)
    {
        if(arr==null||arr.length==0)
            return;
        int sum=0,max=0;
        HashMap<Integer,Integer> hashMap=new HashMap<Integer, Integer>();
        hashMap.put(0,-1);
        //预处理中将(0,-1)放入到hashmap中,可以求出从数组0下标开始的子数组。
        for(int i=0;i<arr.length;i++)
        {
            sum+=arr[i];
            if(!hashMap.containsKey(sum))
            {
                hashMap.put(sum, i);
                //如果当前数组中不存在sum值将其同下标一起放到hashmap中
            }
            if(hashMap.containsKey(sum-k))
            {
            //如果hashmap中存在sum-k由上面的分析可知获取sum-k的value值,
            //从sum-k的value值到当前数组下标是符合条件的子数组区间
                int j=hashMap.get(sum-k)+1;
                for(;j<=i;j++)
                {
                    System.out.print(arr[j]+" ");
                }
                System.out.println();
            }
        }               
    }

解法2的适用更广,不仅可以用在未排序的正整数数组中,还可以适用于数组中出现负值,零值的情况。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值