滑动窗口算法

给定一个整型数组和一个数字s,找到数组中的最短连续子数组,使得连续子数组的和sum>=s,返回这个最短连续子数组的长度值

如给定[2,3,1,2,4,3],s=7

答案为[4,3],返回2

 

第一种解法就是暴力解法,采用双循环来遍历所有的子数组,代码如下

#include<iostream>

using namespace std;

int GetSubArrayLen(int* Arr,int ArrLen,int Val);

int main(void)
{
    int* Array;
    int ArrLen;

    cin >> ArrLen;
    Array = new int[ArrLen];
    for (int i = 0; i < ArrLen; ++i)
        cin >> Array[i];
    int Val;
    cin >> Val;

    cout << GetSubArrayLen(Array, ArrLen, Val)<<endl;
    system("pause");
    return 0;
}

int GetSubArrayLen(int* Arr,int ArrLen,int Val)
{
    int Len = 0;
    int sum = 0;
    for (int t = 0; t < ArrLen; ++t)
        sum += Arr[t];
    if (sum > Val)
        Len = ArrLen;
    else
        return 0;

    for(int i=0;i<ArrLen;++i)
        for (int j = ArrLen - 1; j > i; --j)
        {
            sum = 0;
            for (int t = i; t <= j; ++t)
                sum += Arr[t];
            if(sum>=Val&&((j-i+1)<=ArrLen))
                Len=j-i+1;
        }
    return Len;
}

这种方法的时间复杂度为O(n^3),可以将数组中每个元素的值替换为前面所有数组的和,比如将arr[3]的值变为arr[0]+arr[1]+arr[2]+arr[3],这样求解一段子数组的和时,比如求2~4的子数组之和,就用修改后的arr[4]-arr[2]就可以了,这样可以省去双循环中循环求和步骤门将时间复杂度降到O(n^2)

 

还有一种滑动窗口方法

连个指针L和R,L表示滑窗的左边框,R表示滑窗的右边框

左边框向右滑动使窗口变小,右边框向右滑动使窗口变大,开始左右边框是重合在一起的,窗口的和就是重合点所在的数

1,先将R向右滑动,当和恰好>=s时,记录下滑窗的子数组长度,如果这个长度小于原来的长度,就更新子数组长度

2,L向右滑动,判断是否仍然>=s,如果满足条件就继续向右滑动

3,如果<s则将R向右滑动,重复1

代码如下

#include<iostream>

using namespace std;

int GetSubArrayLen(int* Arr,int ArrLen,int Val);
int WindowValue(int* Arr, int L, int R);

int main(void)
{
    int* Array;
    int ArrLen;

    cin >> ArrLen;
    Array = new int[ArrLen];
    for (int i = 0; i < ArrLen; ++i)
        cin >> Array[i];
    int Val;
    cin >> Val;

    cout << GetSubArrayLen(Array, ArrLen, Val)<<endl;
    system("pause");
    return 0;
}

int GetSubArrayLen(int* Arr,int ArrLen,int Val)
{
    int Len = 0;
    int sum = 0;
    for (int t = 0; t < ArrLen; ++t)
        sum += Arr[t];
    if (sum > Val)
        Len = ArrLen;
    else
        return 0;

    int TempLen = 0;
    int L = 0, R = 0;
    while (R < ArrLen)
    {
        while ((WindowValue(Arr, L, R) < Val)&&(R<ArrLen))
            R++;
        while ((WindowValue(Arr, L, R) >= Val)&&(L<=R))
        {
            TempLen = R - L + 1;
            if (TempLen <= Len)
                Len = TempLen;
            L++;
        }
    }
    return Len;
}

int WindowValue(int* Arr, int L, int R)
{
    int Sum = 0;
    for (int i = L; i < R + 1; ++i)
        Sum += Arr[i];
    return Sum;
}

leetcode 209

给定一个含有 n 个正整数的数组和一个正整数 target 。

找出该数组中满足其和 ≥ target 的长度最小的 连续子数组 [numsl, numsl+1, ..., numsr-1, numsr] ,并返回其长度。如果不存在符合条件的子数组,返回 0 。

 

示例 1:

输入:target = 7, nums = [2,3,1,2,4,3]
输出:2
解释:子数组 [4,3] 是该条件下的长度最小的子数组。
示例 2:

输入:target = 4, nums = [1,4,4]
输出:1
示例 3:

输入:target = 11, nums = [1,1,1,1,1,1,1,1]
输出:0
 

提示:

1 <= target <= 109
1 <= nums.length <= 105
1 <= nums[i] <= 105
 

进阶:

如果你已经实现 O(n) 时间复杂度的解法, 请尝试设计一个 O(n log(n)) 时间复杂度的解法。

class Solution {
public:
    int minSubArrayLen(int target, vector<int>& nums) {
        int size = nums.size();
        if (0 == size)
        {
            return 0;
        }
        int head = 0, tail = 0;
        int sum = 0;
        int len = INT_MAX;
        while (tail < size)
        {
            sum += nums[tail];
            while (sum >= target)
            {
                len = min(len, tail - head + 1);
                sum -= nums[head];
                ++head;
            }
            ++tail;
        }
        return len < INT_MAX ? len : 0;
    }
};

 

posted @ 2020-10-13 23:03  Wangtn  阅读(659)  评论(0编辑  收藏  举报