哈希表【X数之和】

刷题指南

总结(***)

1.循环中降时间复杂度的有:排序 + 双指针,哈希表
2.当出现多个变量时,例如a[i] + a[j] == 0,可以固定j,即找0 ~ j - 1中是否存在 -a[j]这个数,可以边求边统计
3.哈希表:统计出现的次数!
4.双指针:满足单调性时可以考虑双指针

哈希表的常用方法:统计出现的次数

哈希法也是牺牲了空间换取了时间

242. 有效的字母异位词

分析:
用哈希表统计每个字符出现的次数,时间复杂度O(n)。第一次做的时候是直接排序,时间复杂度O(nlogn)
当然这题映射范围比较小,可以拿数组做哈希表。进阶的问题范围大,就不能用数组了吧。
「而且如果哈希值比较少、特别分散、跨度非常大,使用数组就造成空间的极大浪费。」

class Solution {
    
    
public:
    bool isAnagram(string s, string t) {
    
    
        // 时间复杂度O(n)
        // 空间复杂度O(26)
        if(s.size() != t.size()) return false;

        unordered_map<char,int> cnt; // 哈希表
        for(auto c : s) cnt[c] ++;

        for(auto c : t){
    
    
            cnt[c] -- ;
        }

        for(auto x : cnt){
    
    
            if(x.second != 0) return false;
        }
        return true;
    }
};

349. 两个数组的交集

解法1:使用unordered_set

class Solution {
    
    
public:
    vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
    
    
        // 时间复杂度O(n)
        unordered_set<int> num, res;
        for(auto c : nums1) num.insert(c); // 把nums1的元素插到unordered_set中
        
        for(auto c : nums2)
            if(num.count(c)) res.insert(c);
        
        vector<int> ans(res.begin(), res.end()); // 赋值
        return ans;
    }
};

解法2:使用unordered_map

class Solution {
    
    
public:
    vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
    
    
        // 哈希表

        unordered_map<int,int> hash;
        for(auto c : nums1) hash[c] ++ ;

        vector<int> res;
        for(auto c : nums2)
        {
    
    
            if(hash[c] > 0 ) res.push_back(c), hash[c] = 0 ;
        }

        return res;
    }
};

202. 快乐数

分析:
题目中说了会 「无限循环」,那么也就是说「求和的过程中,sum会重复出现,这对解题很重要!」

class Solution {
    
    
public:
    bool isHappy(int n) {
    
    
        unordered_map<int,int> cnt;
        while(n != 1)
        {
    
    
            cnt[n] ++;
            dfs(n); // 引用改变n的值
            if(cnt[n] > 1) return false; // 只要出现次数大于1,说明循环了
        }

        return true;
    }

    void dfs(int &n)
    {
    
    
        int res = 0;
        while(n > 0){
    
    
            int t = n % 10;
            res += t * t;
            n /= 10;
        }
        n = res;
    }
};

1. 两数之和

分析:
一次性统计不太好,边求边插入比较好

class Solution {
    
    
public:
    vector<int> twoSum(vector<int>& nums, int target) {
    
    
        unordered_map<int,int> hash;
        // 边求边插入
        for(int i = 0;i < nums.size();i ++ ){
    
    
            if(hash.count(target - nums[i])) return {
    
    hash[target - nums[i]], i};
            hash[nums[i]] = i;
        }
        return {
    
    -1, -1};
    }
};

454. 四数相加 II

分析:
观察到N = 500,可知最多循环两个数组。常见的处理手法!

class Solution {
    
    
public:
    int fourSumCount(vector<int>& A, vector<int>& B, vector<int>& C, vector<int>& D) {
    
    
        unordered_map<int,int> hash; //  统计 a + b的值出现的次数
        for(int i = 0;i < A.size();i ++ )
            for(int j = 0;j < B.size();j ++)
                hash[A[i] + B[j]] ++;
                
        int res = 0;
        for(int i = 0;i < C.size();i ++ )
            for(int j = 0;j < D.size();j ++)
            {
    
    
                int s = C[i] + D[j];
                if(hash.count(0 - s)) res += hash[0 - s]; // 这里的处理类似 两数之和
            }
        return res;
    }
};

383. 赎金信

class Solution {
    
    
public:
    bool canConstruct(string r, string m) {
    
    
        // 哈希计数
        unordered_map<char,int> cnt;
        for(auto c : m) cnt[c] ++;

        for(auto c : r){
    
    
            cnt[c] -- ;
            if(cnt[c] < 0) return false; // 字符不够了
        }
        return true;
    }
};

15. 三数之和(排序 + 双指针)

分析:排序 + 双指针
哈希表需要去重太难写了,改用排序 + 双指针,事件复杂度O(n ^ 2)
找 a[i] + a[l] + a[r] == 0 ,可以枚举a[i],由于之前排序了,必然满足单调性,随着i移动,l,r都会单调移动,所以可以用双指针。
去重的常用操作:本题的难点也在于去重!

while(l < r && nums[l] == nums[l - 1]) l ++ ;
while(l < r && nums[r] == nums[r + 1]) r -- ;
class Solution {
    
    
public:
    vector<vector<int>> threeSum(vector<int>& nums) {
    
    
        vector<vector<int>> res;

        int n = nums.size();
        if(n < 3) return res;
        sort(nums.begin(), nums.end());

        // a[i] + a[l] + a[r] == 0 , 固定a[i]
        for(int i = 0;i < n;i ++ )
        {
    
    
            if(nums[i] > 0) return res; // 直接返回了
            if(i != 0 && nums[i] == nums[i - 1]) continue; // 去重!关键!
            int l = i + 1, r = n - 1;
            while(l < r)
            {
    
    
                if(nums[l] + nums[i] + nums[r] == 0) {
    
    
                    res.push_back({
    
    nums[i], nums[l], nums[r]});
                    l ++ , r -- ;
                    // 去重的常见操作
                    while(l < r && nums[l] == nums[l - 1]) l ++ ;
                    while(l < r && nums[r] == nums[r + 1]) r -- ;
                }else if(nums[l] + nums[i] + nums[r] < 0){
    
    
                    l ++ ;
                }else{
    
    
                    r -- ;
                }
            }
        }
        return res;
    }
};

18. 四数之和(排序 + 双指针,同三数之和)

分析:时间复杂度O( n 3 n^{3} n3),比四数相加II麻烦在去重处理!
在这里插入图片描述

class Solution {
    
    
public:
    vector<vector<int>> fourSum(vector<int>& nums, int target) {
    
    
        vector<vector<int>> res;
        int n = nums.size();
        sort(nums.begin(), nums.end());
        for(int i = 0;i < n ; i++ )
            for(int j = i + 1;j < n ;j ++ )
            {
    
    
                // 去重        
                if(i != 0 && nums[i] == nums[i - 1]) break;
                if(j != i + 1 && nums[j] == nums[j - 1]) continue; // 这里是continue 
        
                int l = j + 1,r = n - 1;
                while(l < r)
                {
    
    
                    if(nums[i] + nums[j] + nums[l] + nums[r] == target){
    
    
                        res.push_back({
    
    nums[i], nums[j], nums[l], nums[r]});
                        l ++ ,r -- ;
                        while(l < r && nums[l] == nums[l - 1]) l ++ ;
                        while(l < r && nums[r] == nums[r + 1]) r --; 
                        
                    }else if(nums[i] + nums[j] + nums[l] + nums[r] < target) l ++ ;
                    else r -- ;
                }
            }
        
        return res;
    }
};

猜你喜欢

转载自blog.csdn.net/weixin_43154149/article/details/112180592