目录
前言
哈希表基础理论
LeetCode242.有效的字母异位词
LeetCode349.两个数组的交集
LeetCode202.快乐数
LeetCode1.两数之和
一、LeetCode242.有效的字母异位词
题目链接:有效的字母异位词
数组哈希法:
class Solution {
public:
bool isAnagram(string s, string t) {
int strHash[26] = {0};
for(int i = 0; i < s.size(); i++)
{
strHash[s[i] - 'a']++;
}
for(int i = 0; i < t.size(); i++)
{
strHash[t[i] - 'a']--;
}
for(int i = 0; i < 26; i++)
{
if(strHash[i] != 0)
return false;
}
return true;
}
};
代码思路:
由于单词都是由26个英文字母组成,所以采用26个元素的数组可以统计所有单词的字母数量,并且通过str[i] - 'a'可以得到0-25的哈希值。统计完第一个单词的所有字母后,再统计第二个单词与第一个单词的所有字母的数量差值,如果所有字母的数量差值都为0,则两个单词的字母及数量完全一致,返回true,否则返回false。
二、LeetCode349.两个数组的交集
题目链接:两个数组的交集
数组哈希法:
class Solution {
public:
vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
int numHash[1001] = {0};
unordered_set<int> result_set;
for(vector<int>::iterator it = nums1.begin(); it != nums1.end(); it++)
{
numHash[*it] = 1;
}
for(vector<int>::iterator it = nums2.begin(); it != nums2.end(); it++)
{
if(numHash[*it])
{
result_set.insert(*it);
}
}
return vector<int>(result_set.begin(), result_set.end());
}
};
数组哈希表法代码思路:
题目设置了数组元素的范围是[0, 1000],所以我们可以用一个长度为1001的数组来记录出现过数字。因为集合set有天然的去重功能,且unordered_set的底层实现是哈希表,所以查找和插入的时间复杂度都是O(1)
unordered_set哈希表法:
class Solution {
public:
vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
unordered_set<int> hashSet(nums1.begin(), nums1.end());
unordered_set<int> resultSet;
for(int num:nums2)
{
if(hashSet.find(num) != hashSet.end())
resultSet.insert(num);
}
return vector<int>(resultSet.begin(), resultSet.end());
}
};
unordered_set哈希法代码思路:
由于unordered_set底层实现是哈希表,所以查找和增删的效率都是O(1),我们可以不使用数组而改用unordered_set来记录出现过的数字,不过要注意的是相比与数组,使用unordered_set的效率会更低,因为无论是查找还是增删都会比数组额外多出一个哈希值的计算。
三、LeetCode202.快乐数
题目链接:快乐数
unordered_set哈希表法:
class Solution {
public:
int getSumSquares(int n)
{
int sum = 0;
int num;
while(n)
{
num = n % 10;
sum += num * num;
n /= 10;
}
return sum;
}
bool isHappy(int n) {
int sum = n;
unordered_set<int> recordSet;
recordSet.insert(n);
while(1)
{
sum = getSumSquares(sum);
if(sum == 1)
{
return true;
}
if(recordSet.find(sum) != recordSet.end())
{
return false;
}
recordSet.insert(sum);
}
}
};
代码思路:
此题使用unordered_set保存每次平方和的结果,一旦重复出现了某个结果,就说明这个数会一直循环出现,不满足快乐数的要求。
四、LeetCode1.两数之和
题目链接:两数之和
unordered_map哈希表法:
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
unordered_map<int, int> recordMap;
vector<int> retVec(2);
for(int i = 0; i < nums.size(); i++)
{
unordered_map<int, int>::iterator it = recordMap.find(target - nums[i]);
if(it != recordMap.end())
{
retVec[0] = it->second;
retVec[1] = i;
return retVec;
}
//operator[]写法如果key值存在则修改value值,如果key不存在,则添加key和value
recordMap[nums[i]] = i;
//insert写法如果map中已经存在key了,则会直接忽略该插入操作
// recordMap.insert(pair<int, int>(nums[i], i));
}
return retVec;
}
};
代码思路:
设置ordered_map保存的key和value分别时遍历过的nuns中的元素值以及对应元素值的下标。当我们遍历到某个值的时候,可以通过查找键值(target - nums[i])是否存在,如果存在就表示已遍历的元素中存在一个数,这个数跟当前的nums[i]相加可以等于target。
总结:
当题目有需要记录遍历的元素或者记录某些计算结果时,可以首先考虑哈希表的使用,常用的哈希表数据结构有三种:数组,unordered_set,unordered_map。其中数组适合使用再给定范围内的数据记录,unordered_set适合未给定范围的数据记录,且set本身自带去重功能。unordered_map的用法非常类似与数组,可以看成是数据更高级的使用。