ハッシュテーブル[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.2つのアレイの交差

解決策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.2つの数値の合計

分析:
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.4つの数の加算II

分析:最大2つのアレイをループできることが
観察され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. 3つの数値の合計(ソート+ダブルポインター)

分析:並べ替え+ダブルポインター
ハッシュテーブルは重複排除する必要があり、書き込むのが難しすぎます。代わりに並べ替え+ダブルポインターを使用してください。イベントの複雑さは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. 4つの数値の合計(ソート+ダブルポインター、3つの数値の合計と同じ)

分析:時間計算量O(n 3 n ^ {3}n3)、重複排除処理で4つの数字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