📌  相关文章
📜  来自数组的总和为 K 的最小子数组(1)

📅  最后修改于: 2023-12-03 15:40:21.362000             🧑  作者: Mango

来自数组的总和为 K 的最小子数组

当我们需要寻找一个数组中的总和恰好为 K 的最小子数组时,我们可以使用前缀和和哈希表来解决这个问题。在此,我们将介绍两种不同的方法来解决这个问题。

方法一:前缀和和哈希表
思路

首先,我们可以计算数组中每个元素的前缀和,即从数组的第一个元素到当前元素的总和。然后,对于每个前缀和,我们可以计算它与 K 的差值,将差值存入哈希表中。然后,我们可以遍历每个前缀和,查找哈希表中是否存在与当前前缀和相差 K 的前缀和。如果存在这样的前缀和,那么我们就可以通过减去两个前缀和的差值来获得一个总和恰好为 K 的子数组。此外,我们还需要保持一个变量来记录已经找到的子数组中最小的长度。

代码实现
def minSubArrayLen(nums, k):
    prefix_sum = {0: -1}  # 初始化前缀和的哈希表,将前缀和为0的位置设为-1
    sum_i = 0  # 初始化当前的前缀和
    min_len = len(nums) + 1  # 初始化最小子数组的长度为数组的长度加1

    for i in range(len(nums)):
        sum_i += nums[i]
        if sum_i - k in prefix_sum:
            min_len = min(min_len, i - prefix_sum[sum_i - k])
        prefix_sum.setdefault(sum_i, i)  # 如果前缀和不存在,就将当前前缀和和它的位置存入哈希表中

    return min_len if min_len <= len(nums) else 0  # 如果没有找到总和为 K 的子数组,就返回0
时间复杂度

该算法的时间复杂度是 O(n),其中 n 是数组的长度。我们需要遍历数组一次,并在哈希表中查询插入操作是常数时间的。

方法二:双指针法
思路

另一种方法是利用双指针法来解决这个问题。我们可以使用两个指针 i,j 来表示子数组的左右边界。首先,将 j 移动到满足子数组总和大于等于 K 的最小位置,然后再将 i 移动到满足子数组总和小于 K 的最大位置。此时,i 到 j 这个子数组的总和就是恰好为 K 的最小子数组。然后,我们再将 i 右移一位,继续寻找下一个最小子数组。

代码实现
def minSubArrayLen(nums, k):
    i, j = 0, 0  # 初始化双指针
    cur_sum = 0  # 初始化当前子数组的总和
    min_len = len(nums) + 1  # 初始化最小子数组的长度为数组的长度加1

    for j in range(len(nums)):
        cur_sum += nums[j]
        while cur_sum >= k:
            min_len = min(min_len, j - i + 1)
            cur_sum -= nums[i]
            i += 1

    return min_len if min_len <= len(nums) else 0  # 如果没有找到总和为 K 的子数组,就返回0
时间复杂度

该算法的时间复杂度是 O(n),其中 n 是数组的长度。我们需要只遍历数组一次,每个元素最多被访问两次。