当前位置: 首页 > news >正文

华为OD机试 - 寻找连续区间 - 滑动窗口(Java 2024 E卷 100分)

题目描述

给定一个含有 N N N 个正整数的数组,求出有多少个连续子数组(包括单个正整数),其元素之和满足 ∑ ≥ x \sum \geq x x

输入描述
第一行为两个整数 N N N, x x x。其中 0 < N ≤ 1 0 5 0 < N \leq 10^5 0<N105, 0 ≤ x ≤ 1 0 7 0 \leq x \leq 10^7 0x107
第二行包含 N N N 个正整数(每个数 ≤ 100 \leq 100 100

输出描述
输出满足条件的连续子数组个数

输入输出示例

示例 1:
输入:

3 7
3 4 7

输出:

4

解释:
满足条件的子数组为:

  • [ 3 , 4 ] [3,4] [3,4] (和为 7 7 7)
  • [ 3 , 4 , 7 ] [3,4,7] [3,4,7] (和为 14 14 14)
  • [ 4 , 7 ] [4,7] [4,7] (和为 11 11 11)
  • [ 7 ] [7] [7] (和为 7 7 7)

解题思路

  1. 问题分析

    • 需要统计所有满足 ∑ i = l r a i ≥ x \sum_{i=l}^r a_i \geq x i=lraix 的区间 [ l , r ] [l,r] [l,r] 的个数
    • 暴力解法时间复杂度为 O ( N 2 ) O(N^2) O(N2),无法通过大规模数据
  2. 优化思路

    • 利用滑动窗口(双指针)技术
    • 维护窗口和 s u m sum sum,当 s u m ≥ x sum \geq x sumx 时统计有效区间数
  3. 算法流程

    1. 初始化指针 l e f t = 0 left=0 left=0,窗口和 s u m = 0 sum=0 sum=0,计数器 c o u n t = 0 count=0 count=0
    2. 遍历数组,右指针 r i g h t right right 0 0 0 N − 1 N-1 N1
      • a [ r i g h t ] a[right] a[right] 加入 s u m sum sum
      • s u m ≥ x sum \geq x sumx 时:
        • 所有以 r i g h t right right 结尾的子数组 [ l , r i g h t ] [l,right] [l,right] l ≤ l e f t l \leq left lleft)都满足条件
        • 增加计数 c o u n t ← c o u n t + ( N − r i g h t ) count \leftarrow count + (N - right) countcount+(Nright)
        • 移动左指针缩小窗口: s u m ← s u m − a [ l e f t ] , l e f t ← l e f t + 1 sum \leftarrow sum - a[left], left \leftarrow left+1 sumsuma[left],leftleft+1

代码实现

Java
import java.util.Scanner;

// 博主亲测版
public class 寻找连续区间 {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int len = scanner.nextInt();
        int target = scanner.nextInt();
        int[] arr = new int[len];
        for (int i = 0; i < len; i++) {
            arr[i] = scanner.nextInt();
        }
        int sum = 0;
        int tempSum;
        int count = 0;
        for (int right = 0; right < len; right++) {
            sum += arr[right];
            tempSum = sum;
            for (int left = 0; left <= right; left++) {
                if (tempSum >= target) {
                    tempSum -= arr[left];
                    count++;
                }
            }
        }
        System.out.println(count);
    }
}
import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int N = sc.nextInt();
        int x = sc.nextInt();
        int[] a = new int[N];
        for (int i = 0; i < N; i++) a[i] = sc.nextInt();

        int count = 0, left = 0, sum = 0;
        for (int right = 0; right < N; right++) {
            sum += a[right];
            while (sum >= x) {
                count += N - right;
                sum -= a[left++];
            }
        }
        System.out.println(count);
    }
}
Python
n, x = map(int, input().split())
a = list(map(int, input().split()))

count = left = current_sum = 0
for right in range(n):
    current_sum += a[right]
    while current_sum >= x:
        count += n - right
        current_sum -= a[left]
        left += 1

print(count)
C++
#include <iostream>
#include <vector>
using namespace std;

int main() {
    int N, x;
    cin >> N >> x;
    vector<int> a(N);
    for (int i = 0; i < N; i++) cin >> a[i];

    int count = 0, left = 0, sum = 0;
    for (int right = 0; right < N; right++) {
        sum += a[right];
        while (sum >= x) {
            count += N - right;
            sum -= a[left++];
        }
    }
    cout << count << endl;
    return 0;
}
JavaScript
const readline = require('readline');
const rl = readline.createInterface({
    input: process.stdin,
    output: process.stdout
});

let input = [];
rl.on('line', line => {
    input.push(line);
}).on('close', () => {
    const [N, x] = input[0].split(' ').map(Number);
    const a = input[1].split(' ').map(Number);

    let count = 0, left = 0, sum = 0;
    for (let right = 0; right < N; right++) {
        sum += a[right];
        while (sum >= x) {
            count += N - right;
            sum -= a[left++];
        }
    }
    console.log(count);
});

复杂度分析

  • 时间复杂度 O ( N ) O(N) O(N)
    每个元素最多被访问两次(右指针和左指针各一次)
  • 空间复杂度 O ( 1 ) O(1) O(1)
    仅使用常数个额外变量

测试用例

测试用例 1
输入:

5 10
1 2 3 4 5

输出:

9

解释:
满足条件的子数组:
[ 1 , 2 , 3 , 4 ] [1,2,3,4] [1,2,3,4], [ 1 , 2 , 3 , 4 , 5 ] [1,2,3,4,5] [1,2,3,4,5],
[ 2 , 3 , 4 ] [2,3,4] [2,3,4], [ 2 , 3 , 4 , 5 ] [2,3,4,5] [2,3,4,5],
[ 3 , 4 , 5 ] [3,4,5] [3,4,5], [ 4 , 5 ] [4,5] [4,5], [ 5 ] [5] [5]

测试用例 2
输入:

1 100
50

输出:

0

测试用例 3
输入:

4 5
5 1 1 5

输出:

6

问题总结

  1. 关键点

    • 利用滑动窗口维护当前子数组和
    • 当和满足条件时,快速计算以当前右指针结尾的有效子数组数
  2. 算法选择

    • 滑动窗口适用于正数数组的区间和问题
    • 保证线性时间复杂度,适合大规模数据
  3. 扩展思考

    • 如果包含负数,需要改用前缀和+二分查找
    • 类似问题:求满足 ∑ ≤ x \sum \leq x x 的子数组数

相关文章:

  • Python入门(7):Python序列结构-字典
  • Docker容器网络相关设置
  • 【系统移植】 (二)交叉开发环境搭建
  • 【蓝桥杯真题精讲】第 15 届 Python A 组(省赛)
  • dounable to get image ‘nginx:latest‘: error during connect
  • 基于kubernetes构建jenkins+gitlab持续集成
  • Pycharm中Django框架使用{% load static %}模板,HTML报错
  • Postman —— postman实现参数化
  • nmslib 是一个 超快、适用于高维向量的最近邻搜索库,基于 HNSW 算法,被广泛用于 语义搜索、推荐系统、人脸识别等任务
  • 美国队长 [4部合集][2008~2025] 4K 下载
  • 如何部署私有 AI 大模型?(本地 GPU vs 云计算 vs 端侧 AI)
  • Debian系统_主板四个网口1个配置为WAN,3个配置为LAN
  • Nessus 扫描Web服务
  • TypeScript vs. JavaScript:技术对比与核心差异解析
  • 【AI论文】探索基于人类反馈的强化学习中的数据扩展趋势与影响
  • 软考教材重点内容 信息安全工程师 第21章 网络设备安全
  • virsh 的工作原理
  • html实现手势密码
  • mapbox基础,使用geojson加载line线图层,实现铁路黑白间隔效果
  • 【PyTorch】继承 nn.Module 创建简单神经网络
  • 中国社联成立95周年,《中国社联期刊汇编》等研究丛书出版
  • 远洋集团:今年前4个月销售80.9亿元,同比增加13.62%
  • 基金经理调仓引发大金融板块拉升?公募新规落地究竟利好哪些板块
  • 第1现场 | 美国称将取消制裁,对叙利亚意味着什么
  • 七部门:进一步增强资本市场对于科技创新企业的支持力度
  • 美国4月CPI同比上涨2.3%低于预期,为2021年2月来最小涨幅