哈希c++练习题

哈希c++

特点:

1、均匀性,离散性
2、每个输入对应唯一输出
3、每个输出对应的输入不唯一,即不同输入可能对应同一输出。

例子:

问题:Random pool .
插入,删除,随机取数 操作,均未O(1)
实现方法,建立两个相反的哈希表,即倒排索引的概念,删除时,用最后一项替换删除项,以保持哈希值的连续性。
布隆过滤器
大数据,大样本集,对一个集合中的项目做查询。正常方法,建立哈希表,对于内存空间的需求量很大。
布隆过滤器存在失误率。仅存在一种失误,宁可错杀三千,不可放过一个,绝不会放过一个坏人,但是可能冤枉好人,但是黑名单中的绝对不会通过。
实现:
一个样本用k个哈希函数,对应到k个位置。作为黑名单,对于任意一出现过的样本,其对应的K个位置必然全是占用的,若有一个未占用,则说明是新样本。布隆过滤器仅有添加操作,额米有删除操作。
哈希表长度M,哈希函数数目K.参数确定决定性能。
图片: https://uploader.shimo.im/f/eg4BoTmv5E4qmfEI.png

理论长度m(向上取整).对应实际空间占用m/8,实际值m’大于m.
图片: https://uploader.shimo.im/f/rQdQv7PI8LUJZdQr.png
k向上取整,m使用理 论值,得到实际k’。

真实失误率:
图片: https://uploader.shimo.im/f/QMp7RzBaJyYStrTD.png

例题

two-sum

Given an array of integers, find two numbers such that they add up to a specific target number.

The function twoSum should return indices of the two numbers such that they add up to the target, where index1 must be less than index2. Please note that your returned answers (both index1 and index2) are not zero-based.

You may assume that each input would have exactly one solution.

Input: numbers={2, 7, 11, 15}, target=9
Output: index1=1, index2=2

解题思路

将所有数存进哈希表,key 为 数值大小,value 为 数值位置。然后对每一个key从哈希表中搜索 target-key 是否存在,若存在找到结果。注意答案是 target-key =key的情况,使用>来保证搜索到的target-key 和key不是同一个数。

class Solution {
 public:
 
    vector<int> twoSum(vector<int> &numbers, int target) {
        map<int,int> datamap;
        for (int i = 0; i < numbers.size(); ++i) {
            datamap[numbers[i]] = i;
        }
        for (int i = 0; i < numbers.size();i++)
        {  
            map<int,int>::iterator iter = datamap.find(target - numbers[i]);
            if(iter!=datamap.end()&&datamap[target-numbers[i]]>i)
                return {++i, ++iter->second};
        }
        return {0, 0};
    }
};

还可以采用边搜索边存入哈希的情况,则在存入之前判断是否存在target-key,则无需考虑target-key =key的情况。

class Solution {
 public:

    vector<int> twoSum(vector<int> &numbers, int target) {
        map<int,int> datamap;

        for (int i = 0; i < numbers.size(); ++i) { 
            map<int,int>::iterator iter = datamap.find(target - numbers[i]);
            if(iter!=datamap.end())
                return {++iter->second,++i};
            else {
                datamap[numbers[i]] = i;
            }
        }
        return {0, 0};
    }

};

3-sum

Given an array S of n integers, are there elements a, b, c in S such that a + b + c = 0? Find all unique triplets in the array which gives the sum of zero.

Note:

Elements in a triplet (a,b,c) must be in non-descending order. (ie, a ≤ b ≤ c)
The solution set must not contain duplicate triplets.

For example, given array S = {-1 0 1 2 -1 -4},

A solution set is:
(-1, 0, 1)
(-1, -1, 2)

思路1,视为a+b=target 的2-sum 问题。

思路2, 暴力解决,从左往右遍历所有情况。运行时间:52 ms ,804K

class Solution {
public:
	vector<vector<int>> threeSum(vector<int>& nums) {
		sort(nums.begin(), nums.end());
		vector<vector<int>> res;
		if (nums.size() < 3)
			return res;
		for (auto i = nums.begin(); i != nums.end() - 2; i++)
			for (auto j = i + 1; j != nums.end() - 1; j++)
				for (auto k = j+1; k != nums.end(); k++)
					if (*i + *j + *k == 0)
						{res.push_back({ *i,*j,*k });break;}
		sort(res.begin(), res.end());
		res.erase(unique(res.begin(), res.end()), res.end());
		return res;
	}
};

思路3, 排序后用指针从两端夹逼,直接跳过,提高运行效率。47 ms,764K

class Solution {
public:
	vector<vector<int>> threeSum(vector<int>& nums) {
		sort(nums.begin(), nums.end());
		vector<vector<int>> res;
		if (nums.size() < 3)
			return res;
		for (auto i = nums.begin(); i != nums.end() - 2; i++)
		{
			for (auto j = i + 1; j != nums.end() - 1; j++)
			{
				for (auto k = nums.end()-1; k != j; k--)
				{
					if (*i + *j + *k == 0)
					{
						res.push_back({ *i,*j,*k }); break;
					}
				}
			}
		}
		sort(res.begin(), res.end());
		res.erase(unique(res.begin(), res.end()), res.end());
		return res;
	}
};

思路4 根据当前值判断移动哪个指针。41 ms 772K

class Solution {
public:
	vector<vector<int>> threeSum(vector<int>& nums) {
		sort(nums.begin(), nums.end());
		vector<vector<int>> res;
		if (nums.size() < 3)
			return res;
		int var=0;
		for (auto i = nums.begin(); i != nums.end() - 2; i++)
		{
			for (auto j = i + 1; j != nums.end() - 1; j++)
			{
				for (auto k = nums.end()-1; k != j;)
				{	
					var = *i + *j + *k;
					if (var == 0)
					{
					res.push_back({ *i,*j,*k }); break;
					}
					else if (var > 0)       //仍然有可能得到结果,移动右指针
						k--;
					else
						break;             //最大的正数也满足不了条件,移动左指针
				}
			}
		}
		sort(res.begin(), res.end());
		res.erase(unique(res.begin(), res.end()), res.end());
		return res;
	}
};

思路五:排除所有不可能的情况,即均为正数,或均为负数。41 ms

class Solution {
public:
	vector<vector<int>> threeSum(vector<int>& nums) {
		sort(nums.begin(), nums.end());
		vector<vector<int>> res;
		if (nums.size() < 3)
			return res;
		if(nums.front()<0||nums.back()>0)
			return res;
		int var=0;
		for (auto i = nums.begin(); i != nums.end() - 2; i++)
		{
			for (auto j = i + 1; j != nums.end() - 1; j++)
			{
				for (auto k = nums.end()-1; k != j;)
				{	
					var = *i + *j + *k;
					if (var == 0)
					{
					res.push_back({ *i,*j,*k }); break;
					}
					else if (var > 0)       //仍然有可能得到结果,移动右指针
						k--;
					else
						break;             //最大的正数也满足不了条件,移动左指针
				}
			}
		}
		sort(res.begin(), res.end());
		res.erase(unique(res.begin(), res.end()), res.end());
		return res;
	}
};

思路l六:指针移动时,遇到相同数字,可跳过。10 ms 600K

class Solution {
public:
	vector<vector<int>> threeSum(vector<int>& nums) {
		sort(nums.begin(), nums.end());
		vector<vector<int>> res;
		if (nums.size() < 3)
			return res;
		if(nums.front()>0||nums.back()<0)
			return res;
		int var=0;
		for (auto i = nums.begin(); i != nums.end() - 2;)
		{
			    auto j = i + 1; 			
				auto k = nums.end()-1;
				while (j < k)
				{
					var = *i + *j + *k;
					if (var == 0)
					{
						res.push_back({ *i,*j,*k });
						while (--k != j && *k == *(k + 1));
						while (++j != k && *j == *(j - 1));
					}
					else if (var > 0)       //仍然有可能得到结果,移动右指针,跳过相同数
						while (--k != j && *k == *(k + 1));
					else if (var < 0 )
						while (++j != k  && *j == *(j-1));             //最大的正数也满足不了条件,移动左指针,跳过相同数
				}
				while (++i != nums.end() - 2 && *i == *(i - 1));					//跳过相同数
		}
		//sort(res.begin(), res.end());
		//res.erase(unique(res.begin(), res.end()), res.end());
		return res;
	}
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值