真实面经题目 · 原创解析

给定整数数组,如何求和为 m 且长度最短的子数组长度?

求和为 m 的最短连续子数组要先确认数组元素是否都为正,正数数组可用滑动窗口,含负数时要改用前缀和和哈希结构。

出现于:华为 · C/C++

60 秒回答模板

如果数组元素都是正数,可以用滑动窗口:右指针扩展累加 sum,当 sum 大于等于 m 时不断移动左指针收缩,并在 sum 等于 m 时更新最短长度。因为正数保证右移会让和不减、左移会让和不增,窗口具有单调性。若数组可能包含负数,滑动窗口会失效,需要用前缀和记录 prefix[j] - prefix[i] = m,再用哈希表或有序结构寻找最短区间。面试要先问清元素范围,不能默认所有输入都适合滑动窗口。

考点 输入假设
难度 真实面经题
回答目标 讲清方法、边界和追问

深入解析

01

先确认元素范围

题干只说整数数组时要追问是否都是正数。正数、非负数和允许负数会直接决定算法选择,不能只凭示例套滑动窗口。

02

正数数组用滑动窗口

用 left、right 维护连续区间和。right 向右扩大窗口,sum 达到或超过 m 后尝试移动 left 缩短长度,并在等于 m 时记录答案。

03

单调性是成立条件

滑动窗口依赖正数带来的单调性:扩张窗口和增加,收缩窗口和减少。如果有负数,移动指针后区间和可能反向变化,贪心收缩不可靠。

04

负数场景用前缀和

令 prefix[k] 为前 k 个元素和,区间 i 到 j 的和等于 prefix[j] - prefix[i]。寻找 prefix[i] = prefix[j] - m,并让 j - i 尽量小。

05

说明返回策略

如果没有满足条件的子数组,要约定返回 0、-1 或空值。面试时还要说明连续子数组、最短长度、多个答案并列时是否需要输出区间。

javascript

正整数数组下的滑动窗口

function minLengthSubarraySum(nums, target) {
  let left = 0;
  let sum = 0;
  let best = Infinity;

  for (let right = 0; right < nums.length; right += 1) {
    sum += nums[right];
    while (sum >= target) {
      if (sum === target) best = Math.min(best, right - left + 1);
      sum -= nums[left];
      left += 1;
    }
  }

  return best === Infinity ? -1 : best;
}
  • 这段代码只在数组元素为正时成立;如果允许负数,应改用前缀和相关方法。
  • 题目若要求“和至少为 m”而不是“等于 m”,更新答案的条件也要调整。

易错点

  • 不要在未确认元素都是正数时直接使用滑动窗口。
  • 不要只在 sum 等于 m 时收缩,sum 大于 m 时也需要收缩寻找后续可能。
  • 不要漏掉无解返回值和空数组边界。

面试官追问

为什么有负数时滑动窗口会失败?

因为右指针扩展不一定增大区间和,左指针收缩也不一定减小区间和,窗口决策失去单调性。

如果要求和至少为 m 的最短子数组呢?

正数数组仍可滑动窗口;含负数时通常需要前缀和加单调队列处理。

如何输出具体子数组而不只是长度?

更新最短长度时同步保存 bestLeft 和 bestRight,最后按这两个下标截取或返回。