C++——哈希练习题

一、编程题

1.在长度 2N 的数组中找出重复 N 次的元素

链接

给你一个整数数组 nums ,该数组具有以下属性:
nums.length == 2 * n.
nums 包含 n + 1 个 不同的 元素
nums 中恰有一个元素重复 n 次
找出并返回重复了 n 次的那个元素

示例 1:
输入:nums = [1,2,3,3]
输出:3

示例 2:
输入:nums = [2,1,2,5,3,2]
输出:2

示例 3:
输入:nums = [5,1,5,2,5,3,5,4]
输出:5

class Solution {
    
    
public:
    int repeatedNTimes(vector<int>& nums) {
    
    
        unordered_map<int,int> countMap;
        for(auto e : nums)
        countMap[e]++;
        
        for(auto& kv : countMap)
        {
    
    
            if(kv.second == nums.size()/2)
            return kv.first;        
        }                                        
        return -1;

    }
};

nbsp;

2. 两个数组的交集

链接

给定两个数组 nums1 和 nums2 ,返回 它们的交集 。输出结果中的每个元素一定是 唯一 的。我们可以 不考虑输出结果的顺序 。

示例 1:
输入:nums1 = [1,2,2,1], nums2 = [2,2]
输出:[2]

示例 2:
输入:nums1 = [4,9,5], nums2 = [9,4,9,8,4]
输出:[9,4]
解释:[4,9] 也是可通过的

class Solution {
    
    
public:
vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
    
    
// 用unordered_set对nums1中的元素去重
unordered_set<int> s1;
for (auto e : nums1)
s1.insert(e);
// 用unordered_set对nums2中的元素去重
unordered_set<int> s2;
for (auto e : nums2)
s2.insert(e);
// 遍历s1,如果s1中某个元素在s2中出现过,即为交集
vector<int> vRet;
for (auto e : s1)
{
    
    
if (s2.find(e) != s2.end())
vRet.push_back(e);
}
return vRet;
}
};

 
 

二、面试题

给40亿个不重复的无符号整数,没排过序。给一个无符号整数,如何快速判断一个数是否在这40亿个数中。【腾讯】

这40亿个不重复的无符号整数占的空间:约等于15-16G

不能使用:
搜索树和哈希表都不太行(内存中存不下)
排序(O(NlogN)),利用二分查找: logN(数据太大,只能放在磁盘文件上,不好支持二分查找)

方法:
1.遍历,时间复杂度O(N)
2.位图解决——直接定址法 512MB
数据是否在给定的整形数据中,结果是在或者不在,刚好是两种状态,那么可以使用一
个二进制比特位来代表数据是否存在的信息,如果二进制比特位为1,代表存在,为0
代表不存在。(比特位映射标记值)
效率很高

(一)位图应用

1. 给定100亿个整数,设计算法找到只出现一次的整数?

kv的统计次数搜索模型
0次 00
1次 01
2次 10

//位图是标准库中的一个容器
template<size_t N>
class twobitset
{
    
    
public:
void set(size_t x)
{
    
    
bool inset1 = _bs1.test(x);
bool inset2 = _bs2.test(x);

// 00
if (inset1 == false && inset2 == false)
{
    
    
// -> 01
_bs2.set(x);
}
else if (inset1 == false && inset2 == true)
{
    
    
// ->10
_bs1.set(x);
_bs2.reset(x);
}

}

void print_once_num()
{
    
    
for (size_t i = 0; i < N; ++i)
{
    
    
if (_bs1.test(i) == false && _bs2.test(i) == true)
{
    
    
cout << i << endl;
}
}
}

private:
bitset<N> _bs1;
bitset<N> _bs2;
};

void test_bit_set3()
{
    
    
int a[] = {
    
     3, 4, 5, 2, 3, 4, 4, 4, 4, 12, 77, 65, 44, 4, 44, 99, 33, 33, 33, 6, 5, 34, 12 };

twobitset<100> bs;
for (auto e : a)
{
    
    
bs.set(e);
}

bs.print_once_num();
}

2. 给两个文件,分别有100亿个整数,我们只有1G内存,如何找到两个文件交集?

在这里插入图片描述

3. 位图应用变形:1个文件有100亿个int,1G内存,设计算法找到出现次数不超过2次的所有整数

类似题目1;

需要四种状态:
0次 00
1次 01
2次 10
3次 11
再添加一段代码:

else if (inset1 == true && inset2 == false)
{
    
    
// ->11
_bs1.set(x);
_bs2.set(x);
}

 
 

(二)布隆过滤器

1. 给两个文件,分别有100亿个query,我们只有1G内存,如何找到两个文件交集?分别给出

精确算法和近似算法
比如:网络请求、sql语法——本质:字符串

近似:一个文件放到布隆里,再从另外一个文件里看在不在。没有去重和有误判

精确:
哈希切分
假设每个query是30字节,100亿query需要多少空间?——3000亿字节,约等于300G
假设两个文件是A和B。一个是300G
A:依次读取文件A中的query,i = Hash(query)%1000,这个query就进去Ai小文件
B:依次读取文件B中的query,i = Hash(query)%1000,这个query就进去Bi小文件
放到内存的两个set中,编号相同的Ai和Bi小文件找交集即可

核心:因为哈希保证相同query一定进入相同编号的小文件

2. 如何扩展BloomFilter使得它支持删除元素的操作

多个位表示一个位置,做计数处理——这就可以支持删除,但是空间消耗更多,布隆的优势就削弱了。

 
 

(三)哈希切割

统计次数+topk

1. 给一个超过100G大小的log file, log中存着IP地址, 设计算法找到出现次数最多的IP地址?

读取每个ip,i = Hash(ip)%500,这个ip就进入第i个小文件
核心:相同的ip一定进入同一个小文件
依次使用map<string,int>对每个小文件统计次数
不是平均切割

2.与上题条件相同,如何找到top K的IP?

建一个k个值为<io,count>的小堆

猜你喜欢

转载自blog.csdn.net/Ll_R_lL/article/details/128423796