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;
}
相关推荐
feng_you_ying_li2 小时前
C++11可变模板参数,包扩展,emplace系列和push系列的区别
前端·c++·算法
剑挑星河月2 小时前
55.跳跃游戏
数据结构·算法·leetcode
Gofarlic_OMS2 小时前
中小企业控制方法:中小型制造企业Creo许可证成本控制
java·大数据·运维·算法·matlab·制造
星马梦缘2 小时前
快表、页表地址获取+缓存、主存、硬盘数据获取
算法·操作系统·os·tlb
大尚来也2 小时前
Go性能优化实战:如何减少内存分配,榨干每一滴性能
算法
白藏y2 小时前
【C++】ifstream、ofstream、fstream的基础使用
c++
皮卡蛋炒饭.2 小时前
Linux进程信号
开发语言·c++
W23035765732 小时前
算法详解:矩阵连乘问题(动态规划 C++ 完整实现)
算法·动态规划·矩阵连乘