问题描述
给定一个包含 n 个整数的数组和一个目标值 x,需要找到一个连续子数组,使其元素之和大于等于 x。如果有多个满足条件的子数组,通常希望找到长度最短的一个。
解题思路
这道题如果采用暴力枚举所有子数组的方法,时间复杂度会达到 O(n^2),在数据量较大时容易超时。我们可以利用滑动窗口(双指针)的策略将效率优化到 O(n)。
具体做法是维护两个指针 prev 和 cur,分别代表窗口的左边界和右边界。同时用一个变量 sum 来记录当前窗口内元素的总和。
当 sum 小于 x 时,说明当前窗口还不够大,无法覆盖目标值,此时需要扩大窗口,让 cur 向右移动并累加新加入的元素。
一旦 sum 达到或超过 x,我们就找到了一个满足条件的窗口。为了寻找更短的窗口,我们需要尝试收缩左边界,即让 prev 向右移动,并从 sum 中减去移出的元素。在这个过程中,如果发现了比之前记录的更短的有效窗口,就更新最佳位置。
重复上述过程直到 cur 遍历完整个数组。
代码实现
#include <iostream>
#include <vector>
using namespace std;
int main() {
// 读取输入规模 n 和目标值 x
int n, x;
cin >> n >> x;
vector<int> arr(n);
for(int i = 0; i < n; i++) {
cin >> arr[i];
}
// 用于存储最终结果的起始和结束索引
// 初始化为 0,表示尚未找到有效区间
int index[2] = {0};
// 滑动窗口初始化
int cur = 0; // 右指针
int prev = 0; // 左指针
int sum = 0; // 当前窗口和
while(cur < n) {
sum += arr[cur]; // 扩展右边界
// 当窗口和满足条件时,尝试收缩左边界以寻找更优解
(sum >= x) {
(index[] == && index[] == ) {
index[] = prev;
index[] = cur;
sum -= arr[prev++];
;
}
currentLen = cur - prev + ;
bestLen = index[] - index[] + ;
(currentLen < bestLen) {
index[] = prev;
index[] = cur;
}
sum -= arr[prev++];
}
cur++;
}
cout << index[] + << << index[] + << endl;
;
}


