返回

以和最小的子数组及其长度

后端

算法简介

剑指 Offer II 008. 和大于等于 target 的最短子数组

给定一个整数数组和一个目标值target,请你返回一个长度最短的子数组,满足其和大于等于 target。如果不存在这样的子数组,请返回 0

示例 1:

输入:nums = [1, 2, 3, 4, 5], target = 11
输出:3
解释:子数组 [3, 4, 5] 的和为 12,满足大于等于 target 的条件,长度为 3 是最短的。

示例 2:

输入:nums = [1, 1, 1, 1, 1, 1, 1, 1], target = 11
输出:0
解释:没有满足大于等于 target 的子数组。

示例 3:

输入:nums = [1, 2, 3, 4, 5], target = 15
输出:5

提示:

  • 1 <= nums.length <= 10^5
  • 1 <= nums[i] <= 10^5
  • 1 <= target <= 10^9

算法分析

此题可以通过动态规划来解决。我们可以定义一个状态 dp[i],其中 dp[i] 表示前 i 个元素的最小和子数组的长度。我们可以使用以下递推关系来计算 dp[i]

  • dp[0] = 0
  • dp[i] = min(dp[i-1], dp[j] + 1) 其中 j 是满足 sum(nums[j:i]) >= target 的最小索引。

使用此递推关系,我们可以计算出所有 dp[i] 的值,然后找到最小的 dp[i] 值。最小 dp[i] 的索引就是最短子数组的长度。

实现方法

方法一:暴力法

def minSubArrayLen(target, nums):
    """
    :type target: int
    :type nums: List[int]
    :rtype: int
    """
    n = len(nums)
    min_len = n + 1

    for i in range(n):
        current_sum = 0
        for j in range(i, n):
            current_sum += nums[j]
            if current_sum >= target:
                min_len = min(min_len, j - i + 1)
                break

    return min_len if min_len <= n else 0

方法二:动态规划

def minSubArrayLen(target, nums):
    """
    :type target: int
    :type nums: List[int]
    :rtype: int
    """
    n = len(nums)
    dp = [n + 1] * (target + 1)
    dp[0] = 0

    for i in range(1, n + 1):
        for j in range(target, nums[i - 1] - 1, -1):
            dp[j] = min(dp[j], dp[j - nums[i - 1]] + 1)

    min_len = n + 1
    for i in range(target, target + 1):
        min_len = min(min_len, dp[i])

    return min_len if min_len <= n else 0

结语

本文中,我们讨论了 LeetCode 上的剑指 Offer II 008. 和大于等于 target 的最短子数组问题。我们分析了两种不同的解决方案,暴力法和动态规划法。

暴力法是一种简单但效率低下的方法,时间复杂度为 O(n^2)。动态规划法是一种更高效的方法,时间复杂度为 O(n * target)。

在实际应用中,我们可以根据具体情况选择合适的解决方案。