真实面经题目 · 原创解析
给定整数数组,如何求和为 m 且长度最短的子数组长度?
求和为 m 的最短连续子数组要先确认数组元素是否都为正,正数数组可用滑动窗口,含负数时要改用前缀和和哈希结构。
出现于:华为 · C/C++
真实面经题目 · 原创解析
求和为 m 的最短连续子数组要先确认数组元素是否都为正,正数数组可用滑动窗口,含负数时要改用前缀和和哈希结构。
如果数组元素都是正数,可以用滑动窗口:右指针扩展累加 sum,当 sum 大于等于 m 时不断移动左指针收缩,并在 sum 等于 m 时更新最短长度。因为正数保证右移会让和不减、左移会让和不增,窗口具有单调性。若数组可能包含负数,滑动窗口会失效,需要用前缀和记录 prefix[j] - prefix[i] = m,再用哈希表或有序结构寻找最短区间。面试要先问清元素范围,不能默认所有输入都适合滑动窗口。
题干只说整数数组时要追问是否都是正数。正数、非负数和允许负数会直接决定算法选择,不能只凭示例套滑动窗口。
用 left、right 维护连续区间和。right 向右扩大窗口,sum 达到或超过 m 后尝试移动 left 缩短长度,并在等于 m 时记录答案。
滑动窗口依赖正数带来的单调性:扩张窗口和增加,收缩窗口和减少。如果有负数,移动指针后区间和可能反向变化,贪心收缩不可靠。
令 prefix[k] 为前 k 个元素和,区间 i 到 j 的和等于 prefix[j] - prefix[i]。寻找 prefix[i] = prefix[j] - m,并让 j - i 尽量小。
如果没有满足条件的子数组,要约定返回 0、-1 或空值。面试时还要说明连续子数组、最短长度、多个答案并列时是否需要输出区间。
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;
} 因为右指针扩展不一定增大区间和,左指针收缩也不一定减小区间和,窗口决策失去单调性。
正数数组仍可滑动窗口;含负数时通常需要前缀和加单调队列处理。
更新最短长度时同步保存 bestLeft 和 bestRight,最后按这两个下标截取或返回。