昨天,我提交成功了第一道leetcode,用的最简单的暴力法,但也很开心了。今天,我想再来学习一下另外两种使用哈希表的方法,之所以想做leetcode就是因为一道题能学习到多种解法,这种感觉很安逸。
在昨日简单学习了vector的基础上,这次需要用到unordered_map,即无序关联容器,它有一个键值(key value)和一个索引值(mapped value),就好像是函数映射x对应f(x)一样,无序的(unordered)相比正常map,根据其键值能更快检索(retrieve)到需要的数据。
先说过两遍哈希表:
vector<int> twoSum(vector<int>& nums, int target) {
vector<int> res;
unordered_map<int, int> m;
for (int i=0;i<nums.size();i++) {
m[nums[i]]=i;//m[2]=0 m[7]=1 m[11]=2 m[15]=3
}
for (int i=0;i<nums.size();i++) {
int t=target-nums[i];
if (m.count(t)&&m[t]!=i) {
res.push_back(i);
res.push_back(m[t]);
break;
}
}
return res;
}
时间复杂度:O(n) 没有嵌套的for了
空间复杂度:O(n) 取决于哈希表中元素的数量,有n个,课上常听说的空间换时间。
- unordered_map<int, int> m:前面一个int是键值的类型,后面一个int是索引值的类型,很神奇的是它跟string一样大小都是自动变的,所以不用担心超过范围。
- m[nums[i]]=i:testcase测试的数据nums[]={2,7,11,15}有4个元素,按照2-0,7-1,11-2,15-3的映射关系把nums的4个元素装进m这个无序关联容器,别看索引值是0,1,2,3,这个无序指的是键值之间无序,这很关键,这种容器就看准键值进行检索,所以很快。执行完之后容器内部就得到了m[2]=0,m[7]=1,m[11]=2,m[15]=3的关系。
- m.count(t):返回容器中键值与t相同的元素的数量。
- m.count(t)&&m[t]!=i:需要两个条件同时成立,一个条件是与nums[i]相加得到target值的另一个数t能在m容器中存在,另一个条件是一个数不能用两次。满足这两个条件就可以把对应的两个数的indices存入返回的res容器了。
- break:刚开始我还担心会把同组数据存两次,或者有多组符合条件的数据的话怎么样呢,还好题目说明了明确只有一个solution,既然找到了就快逃出循环吧。
接下来是一遍哈希表:
vector<int> twoSum(vector<int>& nums, int target) {
unordered_map<int, int> m;
for(int i=0;i<nums.size();i++){
if(m.count(target-nums[i])){
return { i, m[target-nums[i]] };
}
m[nums[i]]=i;
}
return {};
}
其实也差不多,换汤不换药,就是把第一遍构成哈希表的步骤省去了,然后直接判断m中有没有满足条件的键值(第一次循环肯定没有啦,没有一个元素在哈希表里建立了映射关系),如果找到了就直接return符合条件的index i和键值对应的索引值m[target-nums[i]],否则就把num[i]中的这个元素当作键值装进哈希表,以便后面来的匹配。最后真的一个没找到的话,注意twoSum是一个vector容器,不能return 0,而是空集合{}。
再附下加了main的完整的cpp代码,满足下我的强迫症
#include <iostream>
#include <cstdio>
#include <vector>
#include <unordered_map>
using namespace std;
vector<int> twoSum(vector<int>& nums, int target) {
vector<int> res;
unordered_map<int, int> m;
for (int i=0;i<nums.size();i++) {
m[nums[i]]=i;//m[2]=0 m[7]=1 m[11]=2 m[15]=3
}
for (int i=0;i<nums.size();i++) {
int t=target-nums[i];
if (m.count(t)&&m[t]!=i) {
res.push_back(i);
res.push_back(m[t]);
break;
}
}
return res;
}
int main() {
vector<int> nums;
nums.push_back(2);//nums=[2]
nums.push_back(7);//nums=[2,7]
nums.push_back(11);//nums=[2,7,11]
nums.push_back(15);//nums=[2,7,11,15] nums.size()=4
vector<int> a=twoSum(nums, 9);
cout<<a[0]<<" "<<a[1];
}
有一个问题是,不知道为什么过一遍哈希表的代码在leetcode上accepted了但我的软件上就出错了。。。
这种博客其实算是我给自己在讲思路。但我相信天天游戏的P神如果哪天突然想编程的话还是可以来看看这类博客的。。。天色不早。
(逃)