HJ177 可匹配子段计数

知识点双指针

校招时部分企业笔试将禁止编程题跳出页面,为提前适应,练习时请使用在线自测,而非本地IDE。

描述

给定整数数组 aa(长度 nn)与数组 bb(长度 mm,m≦nm≦n)。设一个长度为 mm 的数组 cc 被称为 可匹配的 ,当且仅当将 cc 的元素重新排列后,与数组 bb 在对应位置上至少有 kk 个元素相等。

对于 aa 中的每一个长度恰为 mm 的连续子段,都可视为一个候选数组 cc。求满足条件的子段数量。

【形式化解释】

若子段 al..l+m−1al..l+m−1​ 经重排可与 bb 至少 kk 个位置相等,则称该子段为"可匹配的"。等价地,设 cntx(S)cntx​(S) 为元素 xx 在序列 SS 中出现次数,则子段 cc 的"匹配度"为 match⁡(c)=∑xmin⁡(cntx(c), cntx(b))match(c)=∑x​min(cntx​(c), cntx​(b)),若 match⁡(c)≧kmatch(c)≧k 则符合要求。

输入描述:

第一行输入整数 t(1≦t≦104)t(1≦t≦104)------测试用例组数。

每个测试用例:

• •​一行三个整数 n,m,k(1≦k≦m≦n≦2×105)n,m,k(1≦k≦m≦n≦2×105);

• •​一行 nn 个整数 a1...an (1≦ai≦106)a1​...an​ (1≦ai​≦106);

• •​一行 mm 个整数 b1...bm (1≦bi≦106)b1​...bm​ (1≦bi​≦106)。

输入保证所有测试用例的 nn 之和、mm 之和均不超过 2×1052×105。

输出描述:

对每个测试用例输出一行整数,表示满足条件的子段数量。

示例1

输入:

复制代码
1
4 1 1
4 1 5 6
6

复制输出:

复制代码
1
cpp 复制代码
#include <iostream>
#include <vector>
#include <map>

using namespace std;

void solve() {
    int n, m, k;
    cin >> n >> m >> k;
    vector<int> a(n);
    map<int, int> mapB;
    for (int i = 0; i < n; ++i) {
        cin >> a[i];
    }
    for (int i = 0; i < m; ++i) {
        int val;
        cin >> val;
        mapB[val]++;
    }

    map<int, int> mapA;
    int current_match = 0;
    int ans = 0;

    // 初始化第一个窗口
    for (int i = 0; i < m; ++i) {
        mapA[a[i]]++;
    }

    for (auto const& [val, countB] : mapB) {
        if (mapA.count(val)) {
            current_match += min(mapA[val], countB);
        }
    }

    if (current_match >= k) {
        ans++;
    }

    // 滑动窗口
    for (int i = m; i < n; ++i) {
        int remove_val = a[i - m];
        int add_val = a[i];

        // 处理移出窗口的元素
        if (mapB.count(remove_val)) {
            if (mapA[remove_val] <= mapB[remove_val]) {
                current_match--;
            }
        }
        mapA[remove_val]--;
        if (mapA[remove_val] == 0) {
            mapA.erase(remove_val);
        }

        // 处理加入窗口的元素
        if (mapB.count(add_val)) {
            if (mapA.count(add_val) < 1 || mapA[add_val] < mapB[add_val]) {
                current_match++;
            }
        }
        mapA[add_val]++;

        if (current_match >= k) {
            ans++;
        }
    }
    cout << ans << endl;
}

int main() {
    int t;
    cin >> t;
    while (t--) {
        solve();
    }
    return 0;
}
相关推荐
AI备案指南-满满27 分钟前
人工智能拟人化互动服务安全自评估报告的评估要点有哪些?
人工智能·算法·安全·机器人·大模型备案·算法备案
土司大王2 小时前
LeetCode hot100——两两交换链表中的节点
算法·leetcode·职场和发展
大熊背3 小时前
树莓派IspPipeline LSC模块原理详解
算法·lsc·isppipeline·mesh lsc
zander2584 小时前
LeetCode 300. 最长递增子序列
算法·leetcode·深度优先
程序员与背包客_CoderZ4 小时前
高性能分布式KV存储引擎RocksDB入门与C/C++编码实战
c语言·开发语言·数据库·c++·分布式·分布式数据库·rocksdb
进击的_鹏4 小时前
从零开始的 Redis 学习
服务器·数据库·c++·redis·缓存
祖力554 小时前
Linux应用软件编程:目录IO与framebuffer
linux·运维·算法·framebuffer·目录io
名字还没想好☜4 小时前
Go 用 slices/maps 标准库泛型函数:告别手写 Contains、Sort、去重(Go 1.21)
开发语言·后端·算法·golang·go
地平线开发者4 小时前
【模型轻量化专题】深度学习模型为什么需要轻量化
算法
_Narcissus_5 小时前
链表算法题和静态链表
数据结构·c++·笔记·算法·链表·ai·力扣