蓝桥杯试题:双指针

一、题目描述


给定一个长度为n的序列 a1,a2,...... ,an 和一个常数S。
对于一个连续区间如果它的区间和大于或等于 S,则称它为美丽的区间。
对于一个美丽的区间,如果其区间长度越短,它就越美丽。
请你从序列中找出最美丽的区间。


输入描述
第一行包含两个整数n,S,其含义如题所述。
接下来一行包含 n个整数,分别表示 a1,a2,......, an

输出描述
输出共一行,包含一个整数,表示最美丽的区间的长度。
若不存在任何美丽的区间,则输出 0。

二、代码展示

package ikun;

import java.util.Scanner;

public class ikun {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        
        // 读取两个整数 n 和 s
        int n = sc.nextInt(); // 数组的长度
        int s = sc.nextInt(); // 目标和
        
        // 读取数组元素
        int[] a = new int[n];
        for (int i = 0; i < n; i++) {
            a[i] = sc.nextInt();
        }
        
        // 初始化滑动窗口的左右指针、当前窗口的和以及最小长度
        int l = 0;       // 左指针,表示窗口的起始位置
        int sum = 0;     // 当前窗口内元素的和
        int r = 0;       // 右指针,表示窗口的结束位置
        int max = n + 1; // 最小子数组长度,初始设为 n+1(一个不可能的最大值)
        
        // 开始滑动窗口遍历数组
        while (r < n){
            sum += a[r]; // 将当前右指针指向的元素加入窗口和
            
            // 当窗口内的和大于等于目标和 s 时,尝试缩小窗口
            while (sum >= s){
                max = Math.min(max, r - l + 1); // 更新最小长度
                sum -= a[l];                    // 移动左指针,缩小窗口,并从和中减去移出的元素
                l++;                            // 左指针右移
            }
            
            r++; // 右指针右移,扩大窗口
        }
        
        // 如果 max 仍为初始值,说明没有满足条件的子数组
        if (max == n + 1){
            max = 0;
        }
        
        // 输出结果
        System.out.println(max);
    }
}

 `max = Math.min(max, r - l + 1);` 持续跟踪和更新

1. 记录当前满足条件的子数组长度:
    当 `sum >= s` 时,意味着当前窗口 `[l, r]` 的元素之和已经达到了或超过了目标和 `s`。
    此时,`r - l + 1` 计算的是当前窗口的长度。

2. 更新最小长度:
    我们希望找到满足条件的**最短**子数组,因此需要比较当前窗口的长度 `r - l + 1` 与之前记录的最小长度 `max`。
    使用 `Math.min(max, r - l + 1)` 可以确保 `max` 始终保存目前为止找到的最小窗口长度。

3. 逻辑流程:
    初始时,`max` 被设置为 `n + 1`,这是一个不可能的最大值,用于在没有找到满足条件的子数组时返回 `0`。
    每当找到一个满足 `sum >= s` 的窗口时,计算其长度并尝试更新 `max`。
    如果当前窗口更短,则 `max` 会被更新为这个新的更小的值;否则,`max` 保持不变。

示例说明

假设我们有以下输入:
n = 5
s = 11
a = [1, 2, 3, 4, 5]

滑动窗口的过程如下:

1. 窗口扩展:
    窗口从 `[1]` 扩展到 `[1, 2, 3, 4, 5]`,此时 `sum = 15` ≥ `11`。
    计算当前窗口长度 `5 - 0 + 1 = 5`,`max` 更新为 `min(6, 5) = 5`。

2. 窗口收缩:
    移动左指针 `l`,窗口变为 `[2, 3, 4, 5]`,`sum = 14` ≥ `11`。
    计算当前窗口长度 `4 - 1 + 1 = 4`,`max` 更新为 `min(5, 4) = 4`。

3. 继续收缩:
    再次移动左指针,窗口变为 `[3, 4, 5]`,`sum = 12` ≥ `11`。
    计算当前窗口长度 `3 - 2 + 1 = 2`,`max` 更新为 `min(4, 2) = 2`。

最终,`max` 的值为 `2`,即最小的满足条件的子数组长度是 `2`(如 `[5, 4]` 或 `[4, 5]`)。

总结

`max = Math.min(max, r - l + 1);` 这一步的关键作用是持续跟踪和更新满足条件的最小子数组长度。通过比较当前窗口长度与之前记录的最小长度,确保 `max` 始终保存最优解。

这一步是滑动窗口算法高效找到最短满足条件子数组的核心所在。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值