209.Minimum Size Subarray Sum(M)

题目描述

给定一个大小为n的正整数数组和一个正整数s,要求找到一个最小的连续子数组之和大于等于s,求这个最小长度,如果不存在则返还0,原题以及例子如下,
这里写图片描述
上面这只是题目的基础要求,不考虑时间复杂度的情况下是比较容易解决的,但是这道题加了两个实现条件,要求能得到时间复杂度为O(n)和O(n * log n)的解法。

————————想直接看题目要求解法的同学请跳往下一条分割线———————————–
首先我先来简单介绍一个坑了我很久的实现方法。
最初考虑到时间复杂度为O(n),我想的方法是先求和得到整个数组的和,然后从两头开始逐渐的减去较小的那个值(因为如果连续数组长度更短,一定包含的是更大的那个值),直到和再也不能减去任何一个数为止,那么我便得到了结果。咋一想,仿佛没什么问题,但仔细一想我括号里的那句话,就会发现这种解法不具有完备性,为什么怎么说呢?如果不理解,可以先看看我举的一个例子。

int s = 13;
int a[] = {1,2,3,7,6,5,2,3};

很明显,在比较3和3的时候,这两个数相等,本来我以为随便取一个就好,但实际上这是不行的,因为这一步的选择将会影响到最终的求解,比如这儿如果选择保留左面的3,那么最终得到的结果长度为3,如果选择保留右面的3,则结果长度为2。
所以这里不完备的原因在于,当遇到两个相等的数时,无法判断这个是否属于解集,如果属于,是左边的数还是右边的数。如果有大佬有判断的方法,麻烦联系我,试了好多方法都没成功。

———————————————–答案分割线———————————————————-

上面那种方法求解无果,我突然想到了另外一种方法,一边求和,一边舍去,保留最小长度。下面我来简单介绍下,我的想法。
我从0开始,连续的求和,知道和大于等于s,这时,我便开始从头开始逐渐的减去一个数,知道和小于s时,如果这个长度+1的和小于最小长度,我便更新最小长度。这个方法和上面方法的思想有些许类似,不过这个方法遍历了所有的可行的长度,所以是可行的,下面直接上代码,

class Solution {
public:
    int minSubArrayLen(int s, vector<int>& nums) {
        int j = 0, i = 0;
        int l = nums.size();
        int sum = 0;
        int min = l + 1;
        while (j < l) {
            while (sum < s) {
                if (j == l)  {
                    if (min == l + 1) {
                        return 0;
                    } else {
                        return min;
                    }
                }
                sum += nums[j];
                ++j;
            }
            while (i <= j && sum >= s) {
                sum -= nums[i];
                ++i;
            }
            min = (j - i + 1) < min ? j - i + 1 : min;

        }

        return min % (l+1);
    }
};

最后,简单介绍下时间复杂度为O(n * log n )的算法,我觉得这个比O(n)的算法还要难想一点。在这里用到了二分查找的思想,我考虑设置一个窗口的大小为k,使这个窗口在数组上滑动,如果能找到这么一个窗口,满足里面数的和大于等于s,那么我便记录下这个长度,缩小窗口大小为原来的一半,如果不满足则增加当窗口的一半大小,最终返还最小长度。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值