青训营X豆包MarsCode刷题 35 小S的倒排索引 | 豆包MarsCode AI 刷题

77 阅读4分钟

问题描述

小S正在帮助她的朋友们建立一个搜索引擎。为了让用户能够更快地找到他们感兴趣的帖子,小S决定使用倒排索引。倒排索引的工作原理是:每个单词都会关联一个帖子ID的列表,这些帖子包含该单词,且ID按从小到大的顺序排列。
例如,单词“夏天”可能出现在帖子1、帖子3和帖子7中,那么这个单词的倒排链就是 [1, 3, 7]。如果用户想同时找到包含“夏天”和“海滩”的帖子,小S需要找出两个倒排链的交集,且将结果按照从大到小的顺序输出。现在,给定两个单词的倒排链数组 a 和 b,请你帮助小S找出同时包含这两个单词的帖子ID,并按从大到小的顺序返回结果。


测试样例

样例1:

输入:a = [1, 2, 3, 7], b = [2, 5, 7]
输出:[7, 2]

样例2:

输入:a = [1, 4, 8, 10], b = [2, 4, 8, 10]
输出:[10, 8, 4]

样例3:

输入:a = [3, 5, 9], b = [1, 4, 6]
输出:[]

样例4:

输入:a = [1, 2, 3], b = [1, 2, 3]
输出:[3, 2, 1]

二、解题思路

核心思路

  1. 使用哈希表统计两个数组中每个元素的出现次数。
  2. 遍历哈希表,筛选出两个数组中都至少出现一次的元素。
  3. 将这些元素按照降序排列后返回。

具体步骤

  1. 统计频率
    遍历数组 ab,将每个数字及其频率存入哈希表 hash

    • 如果一个数字只在一个数组中出现,则它的频率为 1
    • 如果一个数字在两个数组中都出现,则它的频率为 2
  2. 筛选公共元素
    遍历哈希表,选择频率为 2 的元素,这些元素即为公共元素。

  3. 排序输出
    将筛选出的公共元素按照降序排列,形成结果数组。


三、代码实现

C++代码

#include <iostream>
#include <vector>
#include <unordered_map>
#include <algorithm>

using namespace std;

// 比较函数,用于降序排列
bool cmp(pair<int, int> a, pair<int, int> b) {
    return a.first > b.first;
}

// 找出两个数组的公共高频元素
vector<int> solution(vector<int>& a, vector<int>& b) {
    unordered_map<int, int> hash;

    // 统计两个数组中每个数字的频率
    for (const auto& x : a) {
        hash[x]++;
    }
    for (const auto& x : b) {
        hash[x]++;
    }

    // 转换为频率数组,并按频率筛选公共元素
    vector<pair<int, int>> freq(hash.begin(), hash.end());
    sort(freq.begin(), freq.end(), cmp);

    // 结果存储
    vector<int> res;
    for (const auto& x : freq) {
        if (x.second == 2) { // 频率为2表示在两个数组中都存在
            res.emplace_back(x.first);
        }
    }
    return res;
}

int main() {
    vector<int> a1 = {1, 2, 3, 7};
    vector<int> b1 = {2, 5, 7};
    vector<int> res1 = solution(a1, b1);
    cout << (res1 == vector<int>{7, 2}) << endl;

    vector<int> a2 = {1, 4, 8, 10};
    vector<int> b2 = {2, 4, 8, 10};
    vector<int> res2 = solution(a2, b2);
    cout << (res2 == vector<int>{10, 8, 4}) << endl;

    vector<int> a3 = {3, 5, 9};
    vector<int> b3 = {1, 4, 6};
    vector<int> res3 = solution(a3, b3);
    cout << (res3 == vector<int>{}) << endl;

    vector<int> a4 = {1, 2, 3};
    vector<int> b4 = {1, 2, 3};
    vector<int> res4 = solution(a4, b4);
    cout << (res4 == vector<int>{3, 2, 1}) << endl;

    return 0;
}

四、知识总结

C++ 知识点

  1. 哈希表统计
    使用 unordered_map 来存储数字及其频率,时间复杂度为 O(n)O(n)。

    unordered_map<int, int> hash;
    for (const auto& x : a) {
        hash[x]++;
    }
    for (const auto& x : b) {
        hash[x]++;
    }
    
  2. 排序
    使用 sort 函数对 pair 类型的向量按降序排列:

    sort(freq.begin(), freq.end(), cmp);
    
  3. 结果筛选
    根据频率筛选公共元素:

    for (const auto& x : freq) {
        if (x.second == 2) {
            res.emplace_back(x.first);
        }
    }
    

时间复杂度

  • 哈希表统计:O(n + m),其中 nn 和 mm 是两个数组的长度。
  • 排序:O(klog⁡k),kk 为哈希表中元素的个数。
  • 总体复杂度:O(n+m+klog⁡k)。

五、学习建议

  1. 熟悉哈希表操作
    本题的核心是使用哈希表统计元素出现的频率,是处理数组交集、频率统计等问题的基础技能。

  2. 优化代码逻辑
    理解如何筛选目标数据并减少多余操作,提高代码效率。

  3. 多样化测试

    • 考虑空数组、完全不重叠数组等边界情况。
    • 对结果排序的要求要明确。

六、总结

本题通过哈希表统计频率和排序筛选解决了两个数组的公共高频元素问题。它结合了 C++ STL 中的常用数据结构和算法,代码简洁高效,是练习数组和哈希表操作的优秀案例。