目录
1.有效的字母异位词(leetcode 242)
思路
-
建立一个哈希表,并全部初始化为0,扫描其中一个字符串,并对应的把哈希表中的位置的值加1
-
再扫描另外一个字符串,若哈希表中无值,则直接返回false,否则把哈希表中方对应的值减1
-
最后再扫描哈希表,若其中有元素的值不为0,则返回false,则全扫描完后返回true
例题
代码实现
class Solution { public: bool isAnagram(string s, string t) { int check[128] = {0}; for(int i = 0; i < s.size(); i++) check[s[i]]++; for(int i = 0; i < t.size(); i++){ if(check[t[i]] == 0) //当check中的元素不为0时,可以直接返回false return false; check[t[i]]--; } for(int i = 0; i < 128; i++){ if(check[i] != 0) return false; } return true; } };
2.两个数组的交集(leetcode 349)
思路
-
建立一个合适的哈希表,全部初始化为0,扫描其中一个数组,如果存在就把哈希表中对应的数加1
-
再扫描另外一个数组,如果对应的哈希表中的值不为0,则插入结果数组中,但是要避免重复
例题
代码实现
class Solution { public: vector<int> intersection(vector<int>& nums1, vector<int>& nums2) { int check[1001] = {0}; for(int i = 0; i < nums1.size(); i++){ if(check[nums1[i]] == 0) check[nums1[i]]++; } vector<int> ans; for(int i = 0; i < nums2.size(); i++){ //保证结果中的数的唯一性 if(check[nums2[i]] != 0 && find(ans.begin(), ans.end(), nums2[i]) == ans.end()) ans.push_back(nums2[i]); } return ans; } };
3.快乐数(leetcode 202)
思路
-
因为数的拆分中,可能会有,故使用哈希表检测循环,先检测是否出现符合题意的答案,若先出现循环则直接返回false
-
快慢指针法(快指针速度为2,慢指针速度为1),因为快慢指针的特性是如果出现循环,则必然会相遇
例题
思路1代码实现
class Solution { public: bool isHappy(int n) { unordered_set<int> check; while(n != 1){ n = getnum(n); //如果出现循环,就返回false if(find(check.begin(), check.end(), n) != check.end()) return false; check.insert(n); } return true; } //求n每个位置上的数的平方数 int getnum(int n){ int sum = 0; while(n != 0){ int num = n % 10; sum += num*num; n /= 10; } return sum; } };
思路2代码实现
class Solution { public: bool isHappy(int n) { int slow = n; int fast = n; while(slow != 1){ slow = getnum(slow); fast = getnum(fast); fast = getnum(fast); if(slow == fast && slow != 1) return false; } return true; } int getnum(int n){ int sum = 0; while(n != 0){ int num = n % 10; sum += num*num; n /= 10; } return sum; } };
4.两数之和(leetcode 1)
思路
-
建立一个map,为了查找,故以nums数组的值作为键,其索引作为值,其中扫描一遍数组,检查map中是否存在target-nums[i]键,若存在即将其索引与索引i均加入结果数组并返回(答案唯一),否则将以nums[i]为键,i为值插入map中。
例题
代码实现
class Solution { public: vector<int> twoSum(vector<int>& nums, int target) { map<int,int> check; vector<int> ans; for(int i = 0; i < nums.size(); i++){ if(check.find(target-nums[i]) != check.end()){ ans.push_back(check[target-nums[i]]); ans.push_back(i); return ans; } check[nums[i]] = i; } return ans; } };
5.四数之和(leetcode 454)
思路
-
分组遍历,nums1和num2中元素和的所有情况列举并统计相同的个数,用map记录,便于查找和统计,以和为键,个数为值
-
再遍历nums3和nums4,统计两数组中元素的和sum的情况,并统计target-sum在map中出现的总次数即可
例题
代码实现
class Solution { public: int fourSumCount(vector<int>& nums1, vector<int>& nums2, vector<int>& nums3, vector<int>& nums4) { int sum = 0; map<int,int> check; for(int i = 0; i < nums1.size(); i++) for(int j = 0; j < nums2.size(); j++) check[nums1[i]+nums2[j]]++; for(int i = 0; i < nums3.size();i++){ for(int j = 0; j < nums4.size(); j++) if(check.find(0 - nums3[i] - nums4[j]) != check.end()) sum += check[0 - nums3[i] - nums4[j]]; } return sum; } };
6.赎金信(leetcode 383)
思路
-
定义一个哈希表,因为只包含小写字母,故26个即可
-
为了优化算法,先对magazine字符串遍历,统计其对应字母的个数,但是
-
再遍历ransomNote字符串,反方向统计其对应字母的个数,当遍历到magazine中对应字母个数不满足时,
即可返回false
-
若先遍历ransomNote,则需要全遍历完magazine字符串,再遍历一遍哈希表方可求解
例题
代码实现
class Solution { public: bool canConstruct(string ransomNote, string magazine) { int check[26] = {0}; for(int i = 0; i < magazine.size(); i++) check[magazine[i] - 'a']++;//也可为-- for(int i = 0;i < ransomNote.size(); i++){ check[ransomNote[i] - 'a']--;//也可为++ if(check[ransomNote[i] - 'a'] < 0)//也可为>0 return false; } return true; } };
7.三数之和(leetcode 15)
思路
-
本题如果使用哈希表,去重操作会比较复杂,所以采用排序+双指针法
例题
代码实现
class Solution { public: vector<vector<int>> threeSum(vector<int>& nums) { sort(nums.begin(),nums.end()); if(nums[0] > 0) return {}; vector<vector<int>> ans; for(int i = 0; i < nums.size(); i++){ if(nums[i] > 0) //因为是有序的,所以如果第一个数大于0,则不用再找了 break; if(i > 0 && nums[i] == nums[i-1])//去重条件是i>0是因为可能会出现[-1,-1,2]这种情况,i>0,即只找连续重 continue; //复数字中的第一个数的情况 int left = i + 1; int right = nums.size() - 1; while(left < right){ if(nums[i] + nums[left] + nums[right] == 0){ //找到满足的数字时,进行去重处理 ans.push_back({nums[i], nums[left], nums[right]}); while(left < right && nums[left] == nums[left+1]) left++; while(left < right && nums[right] == nums[right-1]) right--; left++; right--; } else if(nums[i] + nums[left] + nums[right] > 0)//由于是排序的,所以>0时进行right右移 right--; else left++;//由于是排序的,所以<0时进行left左移 } } return ans; } };
8.四数之和(leetcode 18)
思路
-
思路与三数之和相同,即排序加双指针,但是应该考虑一些优化的办法,即想办法去重和减少没必要的寻找,比如:
-
排序后连续的四个数的和已经大于target,没必要再寻找
-
排序后的数加上数组末尾的三个数(即第1,2,3大),没必要找
-
例题
代码实现
class Solution { public: //由四个数范围可知,四个数之和可能会超过int能够表示的范围,所以用long vector<vector<int>> fourSum(vector<int>& nums, int target) { if(nums.size() < 4) return {}; sort(nums.begin(), nums.end()); vector<vector<int>> ans; for(int i = 0; i < nums.size()-3; i++){ if(i > 0 && nums[i] == nums[i-1]) continue; if ((long) nums[i] + nums[i + 1] + nums[i + 2] + nums[i + 3] > target) break; if ((long) nums[i] + nums[nums.size()-3] + nums[nums.size()-2] + nums[nums.size()-1] < target) continue; for(int j = i + 1; j < nums.size()-2; j++){ if(j > i + 1 && nums[j] == nums[j-1]) continue; if ((long) nums[i] + nums[j] + nums[j + 1] + nums[j + 2] > target) break; if ((long) nums[i] + nums[j] + nums[nums.size()-2] + nums[nums.size()-1] < target) continue; int left = j + 1; int right = nums.size() - 1; while(left < right){ long sum = (long)nums[i] + nums[j] + nums[left] + nums[right]; if(sum == target){ ans.push_back({nums[i],nums[j],nums[left],nums[right]}); while(left < right && nums[left] == nums[left+1]) left++; while(left < right && nums[right] == nums[right-1]) right--; left++; right--; } else if(sum > target) right--; else left++; } } } return ans; } };
总结
哈希表可以用来记录一些数据,可以用在统计某个元素出现次数、去重等情况。