java解法

滑动窗口的概念:

通过两个指针 start 和 end 来定义一个窗口,窗口表示当前子数组的范围。
指针 end 用于扩展窗口,增加子数组的范围。
指针 start 用于收缩窗口,排除不必要的元素,保证子数组和小于 limit
操作逻辑:

每次将 values[end] 加入当前窗口的和 sum。
如果 sum 大于等于 limit,说明从 start 到 end 的子数组满足条件,而对于当前 end,从 start 到数组末尾的子数组也都满足条件,可以直接计算这些子数组的数量:num - end。
然后收缩窗口,即移动 start 指针并从 sum 中减去 values[start]。
优化:

通过滑动窗口,只需遍历每个元素一次(每个元素最多被加入和移除一次),时间复杂度为
𝑂
(
𝑛
)
O(n),比使用双层循环的暴力方法更高效

import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);

        // 读取数组的大小和目标值
        int num = in.nextInt();
        int limit = in.nextInt();

        // 初始化数组并读取值
        int[] values = new int[num];
        for (int i = 0; i < num; i++) {
            values[i] = in.nextInt();
        }

        // 调用方法计算满足条件的子数组数量并输出结果
        System.out.println(findSubarrays(num, limit, values));
    }

    /**
     * 计算满足条件的子数组数量
     * @param num 数组的长度
     * @param limit 子数组和的目标值
     * @param values 数组
     * @return 满足条件的子数组数量
     */
    public static long findSubarrays(int num, int limit, int[] values) {
        // 定义窗口的起点和终点
        int start = 0, end = 0;

        // 当前窗口的和
        long sum = 0;

        // 满足条件的子数组数量
        long total = 0;

        // 遍历数组,扩展窗口
        while (end < num) {
            // 将当前元素加入窗口
            sum += values[end];

            // 如果当前窗口的和 >= limit
            while (sum >= limit) {
                // 从当前起点到数组末尾的子数组都满足条件
                total += num - end;

                // 缩小窗口,移除窗口的起始值
                sum -= values[start++];
            }

            // 扩展窗口的终点
            end++;
        }

        // 返回总的满足条件的子数组数量
        return total;
    }
}

 class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">

C++解法

滑动窗口的核心思想
使用两个指针 left 和 right 表示滑动窗口的左右边界:

right 指针向右扩展窗口,增加子数组范围。
left 指针向右收缩窗口,减少子数组范围,确保窗口和小于 x。
当窗口内的和 total 大于等于 x 时,说明从 right 到数组末尾的所有子数组都满足条件:

这些子数组以 left 开头,从 right 结束到数组末尾。
子数组数量为 n - right。
在每次确定满足条件的子数组数量后,通过移动 left 指针收缩窗口,同时更新 total。

#include 
#include 

using namespace std;

/**
 * 计算满足条件的子数组数量
 * 
 * @param n 数组的长度
 * @param x 子数组和的目标值
 * @param arr 数组
 * @return 满足条件的子数组数量
 */
long long findIntervals(int n, int x, const vector<int>& arr) {
    long long total = 0; // 当前窗口的总和
    long long count = 0; // 满足条件的子数组数量
    int left = 0;        // 滑动窗口的左边界

    // 遍历数组,right 代表滑动窗口的右边界
    for (int right = 0; right < n; right++) {
        total += arr[right]; // 将当前元素加入窗口

        // 如果窗口和 >= x,则计算满足条件的子数组数量
        while (total >= x) {
            count += n - right; // 从 right 到数组末尾的所有子数组都满足条件
            total -= arr[left]; // 收缩窗口,移除窗口左边界的元素
            left++;             // 左边界右移
        }
    }

    return count; // 返回总的满足条件的子数组数量
}

int main() {
    int n, x;

    // 读取数组长度 n 和目标值 x
    cin >> n >> x;

    // 读取数组元素
    vector<int> arr(n);
    for (int i = 0; i < n; ++i) {
        cin >> arr[i];
    }

    // 调用函数并输出结果
    cout << findIntervals(n, x, arr) << endl;

    return 0;
}

 class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">

C解法

更新中
 class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">

JS解法

滑动窗口:

使用两个指针 left 和 right 表示滑动窗口的左右边界。
right 用于扩展窗口范围,加入当前元素,增加窗口和。
当窗口和大于等于 x 时,收缩窗口,移除左边界元素,减小窗口和。
满足条件时直接计算数量:

如果当前窗口和 total 大于等于 x,说明从 right 到数组末尾的所有子数组都满足条件。可以直接通过 n - right 计算这些子数组的数量。

const readline = require("readline");

const rl = readline.createInterface({
  input: process.stdin,
  output: process.stdout,
});

rl.on("line", (line) => {
  // 初始化输入行存储数组
  if (!this.lines) this.lines = [];
  this.lines.push(line);

  // 当输入达到两行时,处理输入数据
  if (this.lines.length === 2) {
    const [n, x] = this.lines[0].split(" ").map(Number); // 解析第一行,获取数组长度 n 和目标值 x
    const arr = this.lines[1].split(" ").map(Number);   // 解析第二行,获取数组元素

    console.log(findIntervals(n, x, arr)); // 调用核心函数并打印结果
    this.lines = []; // 清空存储的输入数据
  }
});

/**
 * 滑动窗口算法计算满足条件的子数组数量
 *
 * @param {number} n 数组长度
 * @param {number} x 目标值
 * @param {number[]} arr 数组
 * @return {number} 满足条件的子数组数量
 */
function findIntervals(n, x, arr) {
  let total = 0; // 当前窗口的和
  let count = 0; // 满足条件的子数组数量
  let left = 0;  // 滑动窗口的左边界

  // 遍历数组,right 表示滑动窗口的右边界
  for (let right = 0; right < n; right++) {
    total += arr[right]; // 将当前元素加入窗口

    // 当窗口和 >= x 时,计算满足条件的子数组数量
    while (total >= x) {
      count += n - right; // 从 right 到数组末尾的所有子数组都满足条件
      total -= arr[left++]; // 收缩窗口,移除窗口左边界的元素
    }
  }

  return count; // 返回满足条件的子数组总数量
}

 class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">

注意:

如果发现代码有用例覆盖不到的情况,欢迎反馈!会在第一时间修正,更新。
解题不易,如对您有帮助,欢迎点赞/收藏

注:本文转载自blog.csdn.net的CodeClimb的文章"https://blog.csdn.net/CodeClimb/article/details/145185130"。版权归原作者所有,此博客不拥有其著作权,亦不承担相应法律责任。如有侵权,请联系我们删除。
复制链接

评论记录:

未查询到任何数据!