#P3902. 长度最小的子数组
-
ID: 3132
Tried: 53
Accepted: 15
Difficulty: 4
-
算法标签>双指针
长度最小的子数组
解题思路
- 设左右指针
left
、right
表示当前窗口[left, right)
(右端开区间或闭区间实现皆可),并维护窗口内元素和sum
。 - 右指针不断右移累加元素,使窗口和
sum
达到或超过target
; - 一旦
sum >= target
,尝试收缩左端:不断右移left
、同时更新sum
,在仍满足sum >= target
的前提下最小化窗口长度,并更新答案; - 重复上述步骤直到右指针走到数组末尾。
复杂度分析
- 时间复杂度:每个元素被左右指针各访问至多一次,O(n)。
- 空间复杂度:仅常数级变量,O(1)。
代码实现
Python
import sys
# 功能函数:返回和>=target的最短连续子数组长度,不存在则返回0
def min_subarray_len(target, nums):
n = len(nums)
left = 0 # 左指针
window_sum = 0 # 当前窗口和
ans = n + 1 # 记录最短长度,初值设为不可能的大值
for right in range(n): # 右指针扩张
window_sum += nums[right]
# 在满足条件时尽量收缩左端
while window_sum >= target:
ans = min(ans, right - left + 1)
window_sum -= nums[left]
left += 1
return 0 if ans == n + 1 else ans
def main():
data = sys.stdin.read().strip().split()
# 读取 n 和 target
n = int(data[0]); target = int(data[1])
# 读取数组
nums = list(map(int, data[2:2+n]))
print(min_subarray_len(target, nums))
if __name__ == "__main__":
main()
Java
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;
import java.util.StringTokenizer;
public class Main {
// 功能函数:返回和>=target的最短连续子数组长度,不存在则返回0
public static int minSubArrayLen(long target, int[] nums) {
int n = nums.length;
int left = 0; // 左指针
long sum = 0; // 当前窗口和,用long更稳妥
int ans = n + 1; // 记录最短长度
for (int right = 0; right < n; right++) { // 右指针扩张
sum += nums[right];
// 满足条件则尽量收缩左端
while (sum >= target) {
ans = Math.min(ans, right - left + 1);
sum -= nums[left];
left++;
}
}
return ans == n + 1 ? 0 : ans;
}
public static void main(String[] args) throws IOException {
// 按行读取并用StringTokenizer分割,足以应对数据范围
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st1 = new StringTokenizer(br.readLine());
int n = Integer.parseInt(st1.nextToken());
long target = Long.parseLong(st1.nextToken());
int[] nums = new int[n];
StringTokenizer st2 = new StringTokenizer(br.readLine());
for (int i = 0; i < n; i++) {
nums[i] = Integer.parseInt(st2.nextToken());
}
int ans = minSubArrayLen(target, nums);
System.out.print(ans);
}
}
C++
#include <bits/stdc++.h>
using namespace std;
// 功能函数:返回和>=target的最短连续子数组长度,不存在则返回0
int minSubArrayLen(long long target, const vector<int>& nums) {
int n = (int)nums.size();
int left = 0; // 左指针
long long sum = 0; // 当前窗口和
int ans = n + 1; // 记录最短长度
for (int right = 0; right < n; ++right) { // 右指针扩张
sum += nums[right];
// 满足条件时尽量收缩左端
while (sum >= target) {
ans = min(ans, right - left + 1);
sum -= nums[left];
++left;
}
}
return (ans == n + 1) ? 0 : ans;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n;
long long target;
cin >> n >> target;
vector<int> nums(n);
for (int i = 0; i < n; ++i) cin >> nums[i];
cout << minSubArrayLen(target, nums) << '\n';
return 0;
}
题目内容
给定一个正整数 target
和一个只包含正整数的数组 nums
(长度为 n
),请找出和大于等于 target
的最短连续子数组的长度。
若不存在满足条件的子数组,输出 0
。
输入描述
- 第一行:两个整数
n
、target
- 第二行:
n
个正整数,表示数组nums
输出描述
- 一行,一个整数,表示满足条件的最短子数组长度;若不存在则输出
0
。
样例一
输入:
6 7
2 3 1 2 4 3
输出:
2
样例二
输入:
3 4
1 4 4
输出:
1
样例三
输入:
7 11
1 1 1 1 1 1 1
输出:
0
数据范围
- 1≤target≤109
- 1≤n≤105
- 1≤nums[i]≤104