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;
}
相关推荐
Niuguangshuo11 小时前
论文解读:CTC,端到端序列识别的开山之作
算法·语音识别
讳疾忌医丶11 小时前
深度拆解 RocksDB 内核:基于 C++17 的 FIFO 调度状态机与温度阶梯自愈设计
java·c++·算法·架构
2401_8685347811 小时前
OpenStack 架构全景:八个核心组件深度拆解
c++·需求分析
高亦真11 小时前
今天是学习嵌入式的第37天
linux·学习·算法
软件课代表CiCi12 小时前
运行库是什么?电脑缺运行库怎么办?c++运行库缺失修复全攻略
开发语言·c++·windows·电脑·dll修复·dll丢失·运行库
蒸蒸yyyyzwd13 小时前
从面经中学到的三件事
c++·笔记
时时三省13 小时前
【时时三省】计算机c语言二级考试选择题重点
c++
罗西的思考13 小时前
[Agent Memory / 强化学习] MemPO源码学习笔记 --- (2)--- 训练
人工智能·算法·机器学习
深圳市方中禾科技14 小时前
FZH1625 LCD 驱动芯片深度评测与实战指南
算法·led
我不会起名字32215 小时前
一天一道算法题(34):回溯法的经典例题(子集)
java·数据结构·python·算法·golang·深度优先·力扣