哈希表专题

哈希表专题

242.有效的字母异位词

class Solution {
public:
    bool isAnagram(string s, string t) {
        unordered_map<char,int> a,b;
        for(char x : s) a[x]++;
        for(char x : t) b[x]++;
        return a == b; //c++中比较哈希表是否相等是注意比较表中元素是否相等
    }
};

或者不用c++的STL

class Solution {
public:
    bool isAnagram(string s, string t) {
        int record[26] = {0};
        for(int i = 0;i < s.size();i++){
            record[s[i] - 'a']++;
        }
        for(int i = 0;i < t.size();i++){
            record[t[i] - 'a']--;
        }
        for(int i = 0;i < 26;i++){
            // record数组如果有的元素不为零0,说明字符串s和t 一定是谁多了字符或者谁少了字符。
            if(record[i] != 0){
                return false;
            }
        }

        return true;

    }
};

349.两个数组的交集

class Solution {
public:
    vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
        vector<int> res;
        unordered_set<int> Set;
        for(int x : nums1) Set.insert(x);
        for(int x : nums2){
            //发现 nums2 的元素在nums1出现过
            if(Set.count(x)){
                res.push_back(x);//将其放入答案中
                Set.erase(x);//同时将集合中的元素去除
            }
        }
        return  res;

    }
};

202.快乐数


class Solution {
public:
    // 取数值各个位上的单数之和
    int get(int n)
    {
        int res = 0;
        while(n != 0){
            res += (n % 10) *(n % 10);
            n /= 10;
        }
        return res;
    }

    bool isHappy(int n) {
        //快慢指针     回到了判断链表是否有环问题
        int slow = n,fast = get(n);
        while(fast != slow)
        {
            fast = get(get(fast));
            slow = get(slow);
        }
        
        return  fast == 1;

    }
};
//当我们遇到了要快速判断一个元素是否出现集合里的时候,就要考虑哈希法了。
//题目中说了会 无限循环,那么也就是说求和的过程中,sum会重复出现
//这道题目使用哈希法,来判断这个sum是否重复出现,如果重复了就是return false, 否则一直找到sum为1为止。
class Solution {
public:
    // 取数值各个位上的单数之和
    int get(int n)
    {
        int res = 0;
        while(n != 0){
            res += (n % 10) * (n % 10);
            n /= 10;
        }
        return res;
    }

    bool isHappy(int n) {
        unordered_set<int> Set;
        while(1)
        {
            int sum = get(n);
            if(sum == 1) return true;
            // 如果这个sum曾经出现过,说明已经陷入了无限循环了,立刻return false
            if(Set.count(sum)) return false;
            else Set.insert(sum);
            //继续下一轮
            n = sum;
        }
        
    }
};

1.两数之和

class Solution {
public:
    unordered_map<int,int> hash;
    vector<int> twoSum(vector<int>& nums, int target) {
        for(int i = 0;i < nums.size();i++)
        {
            int r = target - nums[i];
            if(hash.count(r))
            {
                return {i,hash[r]};
            }else{
                // 如果没找到匹配对,就把访问过的元素和下标加入到hash中
                hash[nums[i]] = i;
            }
        }
        return {};
        
    }
};

454.四数之和(II)

class Solution {
public:
    int fourSumCount(vector<int>& A, vector<int>& B, vector<int>& C, vector<int>& D) {
        unordered_map<int, int> hash; //key:a+b的数值,value:a+b数值出现的次数
        // 遍历大A和大B数组,统计两个数组元素之和,和出现的次数,放到map中
        for (int a : A) {
            for (int b : B) {
                hash[a + b]++;
            }
        }
        int count = 0; // 统计a+b+c+d = 0 出现的次数
        // 在遍历大C和大D数组,找到如果 0-(c+d) 在map中出现过的话,就把map中key对应的value也就是出现次数统计出来。
        for (int c : C) {
            for (int d : D) {
                if (hash.find(0 - (c + d)) != hash.end()) {
                    count += hash[0 - (c + d)];
                }
            }
        }
        return count;
    }
};

383.赎金信

//  哈希表
class Solution {
public:
    bool canConstruct(string ransomNote, string magazine) {
        unordered_map<char,int> hash;
        // 遍历 magazine 字符串,用哈希表统计每个字母的出现次数
        for(char a : magazine) hash[a]++;
        //然后遍历 rason 字符串,如果发现某个字母的次数为0,返回 false;否则对应字母的出现次数减 1。
        for(char b : ransomNote){
            if(hash[b] == 0) return false;
            else hash[b]--;
        }
        return true;

    }
};
// 数组 
class Solution {
public:
    bool canConstruct(string ransomNote, string magazine) {
        //初始化
        int record[26] = {0};

        if(ransomNote.size() > magazine.size()) return false;
        //通过记录record数据记录 magazine里各个字符出现次数
        for(int i = 0;i < magazine.size();i++) record[magazine[i] - 'a']++;

        for(int j = 0;j < ransomNote.size();j++){
            // 遍历ransomNote,在record里对应的字符个数做--操作
            record[ransomNote[j] - 'a']--;
            // 如果小于零说明ransomNote里出现的字符,magazine没有
            if(record[ransomNote[j] - 'a'] < 0) return false;
        }
        return true;

    }
};

15.三数之和

算法分析
排序 + 双指针

1、枚举每个数,表示该数nums[i]已被确定,在排序后的情况下,通过双指针l,r分别从左边l = i + 1和右边n - 1往中间靠拢,找到nums[i] + nums[l] + nums[r] == 0的所有符合条件的搭配
2、在找符合条件搭配的过程中,假设sum = nums[i] + nums[l] + nums[r]
若sum > 0,则r往左走,使sum变小
若sum < 0,则l往右走,使sum变大
若sum == 0,则表示找到了与nums[i]搭配的组合nums[l]和nums[r],存到ans中
3、判重处理
确定好nums[i]时,l 需要从i + 1开始
当nums[i] == nums[i - 1],表示当前确定好的数与上一个一样,需要直接continue
当找符合条件搭配时,即sum == 0,需要对相同的nums[l]和nums[r]进行判重出来

class Solution {
public:
    vector<vector<int>> threeSum(vector<int>& nums) {
        vector<vector<int>> res;
        sort(nums.begin(),nums.end());
        //确定第一个数
        for(int i = 0;i < nums.size();i++)
        {
            // 对第一个数去重
            if(i > 0 && nums[i] == nums[i - 1]) continue;
            int l = i + 1,r = nums.size() - 1;
            while(l < r)
            {
                int sum = nums[i] + nums[l] + nums[r];
                if(sum < 0) l++;
                else if(sum > 0) r--;
                else {
                    res.push_back({nums[i],nums[l],nums[r]});
                    //去重 
                    do {l++;} while (l < r && nums[l] == nums[l - 1]);
                    do {r--;} while (l < r && nums[r] == nums[r + 1]);
                }
                
            }
        }
        return res;
        
    }
};

18.四数之和

与上面的三数之和思路相同,在上题基础上多了一层循环。

算法分析
排序 + 双指针

1、与三数之和操作类似,枚举每两个数,表示该数nums[i]和nums[j]已被确定,在排序后的情况下,通过双指针l,r分别从左边l = i + 1和右边n - 1往中间靠拢,找到nums[i] + nums[j] + nums[l] + nums[r] == target的所有符合条件的搭配
2、在找符合条件搭配的过程中,假设sum = nums[i] + nums[j] + nums[l] + nums[r]
若sum > target,则r往左走,使sum变小
若sum < target,则l往右走,使sum变大
若sum == target,则表示找到了与nums[i]搭配的组合nums[l]和nums[r],存到ans中
3、判重处理
确定好nums[i]时,l 需要从i + 1开始
当nums[i] == nums[i - 1],表示当前确定好的数与上一个一样,需要直接continue
当nums[j] == nums[j - 1],表示当前确定好的数与上一个一样,需要直接continue
当找符合条件搭配时,即sum == 0,需要对相同的nums[l]和nums[r]进行判重出来

class Solution {
public:
    vector<vector<int>> fourSum(vector<int>& nums, int target) {
        vector<vector<int>> res;
        sort(nums.begin(),nums.end());
        for(int i = 0;i < nums.size();i++)
        {
            if(i > 0 && nums[i] == nums[i - 1]) continue;
            for(int j = i + 1;j < nums.size();j++)
            {
                if(j > i + 1 && nums[j] == nums[j - 1]) continue;
                int l = j + 1,r = nums.size() - 1;
                while(l < r)
                {
                    //防止溢出
                    long sum = (long)nums[i] + nums[j] + nums[l] + nums[r];
                    if(sum > target) r--;
                    else if(sum < target) l++;
                    else {
                        res.push_back({nums[i],nums[j],nums[l],nums[r]});
                        do{l++;} while(l < r && nums[l] == nums[l - 1]);
                        do{r--;} while(l < r && nums[r] == nums[r + 1]);
                    }
                }
            }
        }
        return res;

    }
};
  • 10
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值