代码随想录一刷——哈希表篇

目录

1.有效的字母异位词(leetcode 242)

2.两个数组的交集(leetcode 349)

3.快乐数(leetcode 202)

4.两数之和(leetcode 1)

5.四数之和(leetcode 454)

6.赎金信(leetcode 383)

7.三数之和(leetcode 15)

8.四数之和(leetcode 18)

总结


1.有效的字母异位词(leetcode 242)

思路

  1. 建立一个哈希表,并全部初始化为0,扫描其中一个字符串,并对应的把哈希表中的位置的值加1

  2. 再扫描另外一个字符串,若哈希表中无值,则直接返回false,否则把哈希表中方对应的值减1

  3. 最后再扫描哈希表,若其中有元素的值不为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)

思路

  1. 建立一个合适的哈希表,全部初始化为0,扫描其中一个数组,如果存在就把哈希表中对应的数加1

  2. 再扫描另外一个数组,如果对应的哈希表中的值不为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)

思路

  1. 因为数的拆分中,可能会有,故使用哈希表检测循环,先检测是否出现符合题意的答案,若先出现循环则直接返回false

  2. 快慢指针法(快指针速度为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)

思路

  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)

思路

  1. 分组遍历,nums1和num2中元素和的所有情况列举并统计相同的个数,用map记录,便于查找和统计,以和为键,个数为值

  2. 再遍历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)

思路

  1. 定义一个哈希表,因为只包含小写字母,故26个即可

  2. 为了优化算法,先对magazine字符串遍历,统计其对应字母的个数,但是

  3. 再遍历ransomNote字符串,反方向统计其对应字母的个数,当遍历到magazine中对应字母个数不满足时,

    即可返回false

  4. 若先遍历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)

思路

  1. 本题如果使用哈希表,去重操作会比较复杂,所以采用排序+双指针法

例题

代码实现

 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)

思路

  1. 思路与三数之和相同,即排序加双指针,但是应该考虑一些优化的办法,即想办法去重和减少没必要的寻找,比如:

    • 排序后连续的四个数的和已经大于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;
     }
 };

总结

哈希表可以用来记录一些数据,可以用在统计某个元素出现次数、去重等情况。

  • 22
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值