Skip to content

Latest commit

 

History

History
330 lines (268 loc) · 7.76 KB

File metadata and controls

330 lines (268 loc) · 7.76 KB

English Version

题目描述

给定一个含有 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)) 时间复杂度的解法。

解法

方法一:前缀和 + 二分查找

先求出数组的前缀和 s,然后根据 s[j] - s[i] >= target => s[j] >= s[i] + target,找出最小的一个 j,使得 s[j] 满足大于等于 s[i] + target,然后更新最小长度即可。

时间复杂度 $O(NlogN)$

方法二:滑动窗口

使用指针 left, right 分别表示子数组的开始位置和结束位置,维护变量 sum 表示子数组 nums[left...right] 元素之和。初始时 left, right 均指向 0。每一次迭代,将 nums[right] 加到 sum,如果此时 sum >= target,更新最小长度即可。然后将 sum 减去 nums[left],接着 left 指针右移直至 sum < target。每一次迭代最后,将 right 指针右移。

时间复杂度 $O(N)$

Python3

前缀和 + 二分查找:

class Solution:
    def minSubArrayLen(self, target: int, nums: List[int]) -> int:
        s = [0] + list(accumulate(nums))
        n = len(nums)
        ans = n + 1
        for i, v in enumerate(s):
            t = v + target
            j = bisect_left(s, t)
            if j != n + 1:
                ans = min(ans, j - i)
        return 0 if ans == n + 1 else ans

滑动窗口:

class Solution:
    def minSubArrayLen(self, target: int, nums: List[int]) -> int:
        n = len(nums)
        left = right = 0
        sum, res = 0, n + 1
        while right < n:
            sum += nums[right]
            while sum >= target:
                res = min(res, right - left + 1)
                sum -= nums[left]
                left += 1
            right += 1
        return 0 if res == n + 1 else res

Java

前缀和 + 二分查找:

class Solution {
    public int minSubArrayLen(int target, int[] nums) {
        int n = nums.length;
        int[] s = new int[n + 1];
        for (int i = 0; i < n; ++i) {
            s[i + 1] = s[i] + nums[i];
        }
        int ans = n + 1;
        for (int i = 0; i < n; ++i) {
            int t = s[i] + target;
            int left = 0, right = n + 1;
            while (left < right) {
                int mid = (left + right) >> 1;
                if (s[mid] >= t) {
                    right = mid;
                } else {
                    left = mid + 1;
                }
            }
            if (left != n + 1) {
                ans = Math.min(ans, left - i);
            }
        }
        return ans == n + 1 ? 0 : ans;
    }
}

滑动窗口:

class Solution {
    public int minSubArrayLen(int target, int[] nums) {
        int n = nums.length;
        int left = 0, right = 0;
        int sum = 0, res = n + 1;
        while (right < n) {
            sum += nums[right];
            while (sum >= target) {
                res = Math.min(res, right - left + 1);
                sum -= nums[left++];
            }
            ++right;
        }
        return res == n + 1 ? 0 : res;
    }
}

C++

前缀和 + 二分查找:

class Solution {
public:
    int minSubArrayLen(int target, vector<int>& nums) {
        int n = nums.size();
        vector<int> s(n + 1);
        for (int i = 0; i < n; ++i) s[i + 1] = s[i] + nums[i];
        int ans = n + 1;
        for (int i = 0; i < n; ++i) {
            int t = s[i] + target;
            auto p = lower_bound(s.begin(), s.end(), t);
            if (p != s.end()) {
                int j = p - s.begin();
                ans = min(ans, j - i);
            }
        }
        return ans == n + 1 ? 0 : ans;
    }
};

滑动窗口:

class Solution {
public:
    int minSubArrayLen(int target, vector<int>& nums) {
        int left = 0, right;
        int sum = 0;
        int minlen = INT_MAX;

        for (right = 0; right < nums.size(); right++) {
            sum += nums[right];
            while (left <= right && sum >= target) {
                minlen = min(minlen, right - left + 1);
                sum -= nums[left++];
            }
        }

        return minlen == INT_MAX ? 0 : minlen;
    }
};

Go

前缀和 + 二分查找:

func minSubArrayLen(target int, nums []int) int {
	n := len(nums)
	s := make([]int, n+1)
	for i, v := range nums {
		s[i+1] = s[i] + v
	}
	ans := n + 1
	for i, v := range s {
		t := v + target
		left, right := 0, n+1
		for left < right {
			mid := (left + right) >> 1
			if s[mid] >= t {
				right = mid
			} else {
				left = mid + 1
			}
		}
		if left != n+1 && ans > left-i {
			ans = left - i
		}
	}
	if ans == n+1 {
		return 0
	}
	return ans
}

C#

滑动窗口:

public class Solution {
    public int MinSubArrayLen(int target, int[] nums) {
        int n = nums.Length;
        int left = 0, right = 0;
        int sum = 0, res = n + 1;
        while (right < n)
        {
            sum += nums[right];
            while (sum >= target)
            {
                res = Math.Min(res, right - left + 1);
                sum -= nums[left++];
            }
            ++right;
        }
        return res == n + 1 ? 0 : res;
    }
}

TypeScript

function minSubArrayLen(target: number, nums: number[]): number {
    const n = nums.length;
    let res = n + 1;
    let sum = 0;
    let i = 0;
    for (let j = 0; j < n; j++) {
        sum += nums[j];
        while (sum >= target) {
            res = Math.min(res, j - i + 1);
            sum -= nums[i];
            i++;
        }
    }

    if (res === n + 1) {
        return 0;
    }
    return res;
}

Rust

impl Solution {
    pub fn min_sub_array_len(target: i32, nums: Vec<i32>) -> i32 {
        let n = nums.len();
        let mut res = n + 1;
        let mut sum = 0;
        let mut i = 0;
        for j in 0..n {
            sum += nums[j];

            while sum >= target {
                res = res.min(j - i + 1);
                sum -= nums[i];
                i += 1;
            }
        }
        if res == n + 1 {
            return 0;
        }
        res as i32
    }
}

...