Minimum Size Subarray Sum-最小长度字数组和问题

  • 问题描述:Given an array of n positive integers and a positive integer s, find the minimal length of a subarray of which the sum ≥ s. If there isn't one, return 0 instead. <p>For example, given the array [2,3,1,2,4,3] and s = 7,the subarray [4,3] has the minimal length under the problem constraint.</p> <p>More practice:

    If you have figured out the O(n) solution, try coding another solution of which the time complexity is O(n log n).</p>

  • 问题分析:刚开始看到这个题时,并没有考虑到字数组连续的问题,发现只能用递归的解法,复杂度很高,后来搜了下,发现其实是自己理解的问题,这个题必须考虑到连续的问题。
  • Solution 1: 这样O(n)的解法就很明显了,滑动窗口,两个指针即可解决。对数组中的每个数(左指针),计算从它开始往右的和,直到不小于s为止(右指针),然后更新这个长度,随后左指针右移,直至从当前左指针到右指针的和小于s为止。此外,这个题可能发生整个数组和小于s的情况,所以只需要在minLen的初始值设置为大于nums.legth,最后在发挥至的时候判断下即可解决。
  • For example:对当前例子中的数组,left = 0, right = 3.即从2到下一个2为止这个字数组和(8)是超出s(8),然后left右移, 发现left=1时,字数组和变味了8-2=6,所以 从当前的左指针开始,右指针开始移动.这样不断更新这个值即可。代码如下:
    public class Solution {
        public int minSubArrayLen(int s, int[] nums) {
            if (nums == null || s <= 0)
                return 0;
           //滑动窗口
           int left = 0, right = 0, len = nums.length + 1, temp = 0;
           while(right < nums.length){
               while(right < nums.length && temp < s){
                   temp += nums[right++];
               }
               while(temp >= s){
                    len = Math.min(len, right - left);
                    temp -= nums[left++];
               }
           }
           return len == nums.length + 1? 0 : len;
        }
    }


  • Solution 2:more practice要求给出O(nlogn)的解法,实在是很不明白,这个题O(n)的解法已经非常清晰明了,为何还要给出复杂度高的解法,可既然是题目要求,那就尝试接下去,看到log(n),首先就想到了二分查找,可是如何利用二分查找,因为二分查找要求查找的数组有序,那就让数组变得有序即可。让数组变得有序秩序再申请一个数组sums, 其中sums[i] 代表nums[0...i-1]的和。这样对么个sums[i],计算右边界即可。右边界是sums[high] >sums[low] + s的值。其实从这既可以看出,这有解法一并没有本质的区别.另外,这个解法还要注意,一旦sums[low] + s超出了sums[sums.length-1],即说明后边不肯能有满足条件的解了,停止搜索.代码如下:
    public class Solution {
        public int minSubArrayLen(int s, int[] nums) {
            if (nums == null || s <= 0)
                return 0;
            int[] sums = new int[nums.length + 1];
            for(int i = 1; i <= nums.length; i++){
                sums[i] = sums[i-1] + nums[i-1];
            }
            if(sums[sums.length - 1] < s)
                return 0;
            int len = sums.length,low, high, target, mid;
            for(int i = 0; i < sums.length; i++){
                low = i+ 1;high = sums.length-1; target = sums[i] + s;
                while(low <= high){
                    mid = low + ((high - low) >> 1);
                    if(sums[mid] >= target)
                        high = mid - 1;
                    else if (sums[mid] < target)
                        low = mid + 1;
                }
                if(low >= sums.length)
                    break;
                if(low - i < len)
                    len = low - i;
            }
            return len;
        }
    }


    此外,本文的解法在http://www.cnblogs.com/grandyang/p/4501934.html的基础上而来,特此声明。
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值