1 Star 1 Fork 0

刘文韬 / leetcode-note

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
哈希表.md 15.92 KB
一键复制 编辑 原始数据 按行查看 历史
刘文韬 提交于 2020-11-27 10:32 . dd

⚗哈希表⚗

C++哈希表的基本使用

  • 查找元素是否存在
    若有unordered_map<int, int> mp;
    查找x是否在map
    方法1:  若存在  mp.find(x)!=mp.end()
    方法2:  若存在  mp.count(x)!=0
  • 遍历map
    unordered_map<key,T>::iterator it;
    (*it).first;        
    (*it).second  
    for(unordered_map<key,T>::iterator iter=mp.begin();iter!=mp.end();iter++)
          cout<<"key value is"<<iter->first<<" the mapped value is "<< iter->second;
  • 用高级for循环时
    for(auto& it : mp){
        cout<< it.first <<it.second;
}

两数之和

Leetcode给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标。 你可以假设每种输入只会对应一个答案。但是,数组中同一个元素不能使用两遍

解题思路

  • 一次遍历法
  • 如果发现满足条件的key值就return它得值出去,没发现就加入map中
    vector<int> twoSum(vector<int>& nums, int target) {
        unordered_map<int, int> hash;
        for (int i = 0; i < nums.size(); ++i) {
            if (hash.find(target - nums[i]) != hash.end()) {
                return vector<int>{hash[target - nums[i]], i};
            }
            hash[nums[i]] = i;
        }
        return {};
    }

同构字符串

leetcode给定两个字符串 s 和 t,判断它们是否是同构的。 如果 s 中的字符可以被替换得到 t ,那么这两个字符串是同构的。 所有出现的字符都必须用另一个字符替换,同时保留字符的顺序。两个字符不能映射到同一个字符上,但字符可以映射自己本身。

解题思路

  • 哈希交叉映射
  • 比如对于tit和pap,对于tit所有的t对应p,所有的i对应a。对于pap所有的p对应t,所有的a对应i
  • 同时遍历两个字符串,就去map中寻找 该字母是否有对应值(映射),
  • 如果有就去查该映射的值是否与另一个字符串中对应位字母相同,如果不同就不是同构字符串
    bool isIsomorphic(string s, string t) {
        if (s.size() != t.size()) return false;
        unordered_map<char, char> shash;
        unordered_map<char, char> thash;
        for (int i = 0; s[i] != '\0'; ++i) {
            if (shash.find(s[i]) != shash.end() && shash[s[i]] != t[i]) return false;
            if (thash.find(t[i]) != thash.end() && thash[t[i]] != s[i]) return false;
            shash[s[i]] = t[i];
            thash[t[i]] = s[i];
        }
        return true;
    }

存在重复元素

Leetcode给定一个整数数组,判断是否存在重复元素。 如果任意一值在数组中出现至少两次,函数返回 true 。如果数组中每个元素都不相同,则返回 false 。

解题思路

  • 哈希表建立每个数字出现的频率
  • 大于1说明重复
    bool containsDuplicate(vector<int>& nums) {
        unordered_map<int, int> frequence;
        for(auto it : nums){
            if(++frequence[it] > 1) 
                return true;
        }
        return false;
    }

有效的字母异位词

leetcode给定两个字符串 s 和 t ,编写一个函数来判断 t 是否是 s 的字母异位词。

示例

输入: s = "anagram", t = "nagaram"
输出: true

解题思路

  • 对字符串s建立字母的哈希频率表,再遍历t串,对应的字母频率-1,最后遍历哈希表,如果仍有字母频率不为0,说明有多余的字母。
    bool isAnagram(string s, string t) {
        if (s.size() != t.size()) return false;
        unordered_map<int, int> hash;
        for (int i = 0; s[i] != '\0'; ++i) {
            hash[s[i]]++;
        }
        for (int i = 0; t[i] != '\0'; ++i) {
            hash[t[i]]--;
        }
        for (auto it : hash) {
            if (it.second) return false;
        }
        return true;
    }

前K个高频元素

leetcode给定一个非空的整数数组,返回其中出现频率前 k 高的元素。

示例

输入: nums = [1,1,1,2,2,3], k = 2
输出: [1,2]

解题思路

  • 建立哈希表统计数字出现频率,
  • 利用隐式转换,把无序hash转换为pair类型方便按照频率多少进行排序
  • 使用SLT的sort()函数进行排序,大小的比较规则cmp函数需要自己写。
  • 将排好序的前k元素输出
    static bool cmp(pair<int, int> v1, pair<int, int> v2){
        return v1.second > v2.second;
    }
    vector<int> topKFrequent(vector<int>& nums, int k) {
        unordered_map<int,int> hash;
        for (int i = 0; i < nums.size(); ++i) {
            hash[nums[i]]++;
        }
        vector<pair<int, int> > arr(hash.begin(), hash.end());
        sort(arr.begin(), arr.end(), cmp);
        vector<int> res;
        for(int i = 0; i < k; ++i){
            res.push_back(arr[i].first);
        }
        return res;
    }

最长回文串

leetcode给定一个包含大写字母和小写字母的字符串,找到通过这些字母构造成的最长的回文串。 在构造过程中,请注意区分大小写。比如 "Aa" 不能当做一个回文字符串。

解题思路

  • 根据题意,只需求出最长回文串的长度,而不需要找出最长回文串,所以我们只需利用回文串的特性,统计哪些字母出现了偶数次,哪些出现了奇数次,只需计算他们次数即可。
  • 出现偶数次的字母一定是回文串的一部分,奇数次的字母只需-1次也能组成回文串,最后如果组成的回文串长度小于母串,还可以再再中间加一个字母组成回文串。
    int longestPalindrome(string s) {
        unordered_map<char,int> hash;
        for (auto it : s) {
            hash[it]++;
        }
        int res = 0;
        for (auto it : hash) {
           res += it.second % 2 == 0 ? it.second : it.second - 1;
        }
        return res = res < s.size() ? res + 1 : res ;
    }

根据字符出现频率排序

leetcode给定一个字符串,请将字符串里的字符按照出现的频率降序排列。

解题思路

  • 哈希表建立的频率表是无序的,所以需要转换为其他数据结构,再使用排序算法对其排序
  • 可以使用隐式的类型转换为pair<char,int>,再使用STL里面的sort()函数进行排序,sort的好处是可以自定义排序的规则。
  • sort()函数自定义的排序规则需要写成静态的函数
    static bool cmp(pair<char, int> a, pair<char, int> b) {
        return a.second > b.second;
    }
    string frequencySort(string s) {
        unordered_map<char, int>hash;
        for (auto it : s) {
            hash[it]++;
        }
        vector<pair<char, int> > arr(hash.begin(), hash.end());
        sort(arr.begin(), arr.end(), cmp);
        string res;
        for (auto it : arr) {
            while (it.second--) {
                res.push_back(it.first);
            }
        }
        return res;
    }

最长和谐子序列

Leetcode 和谐数组是指一个数组里元素的最大值和最小值之间的差别正好是1。
现在,给定一个整数数组,你需要在所有可能的子序列中找到最长的和谐子序列的长度。

示例

输入: [1,3,2,2,5,2,3,7]
输出: 5
原因: 最长的和谐数组是:[3,2,2,2,3].

解题思路

  • 找最长的长度,一定需要一个数字去记录当前最长值,并不断跟后面的数进行比较
  • 统计数字出现频率,遍历哈希表的每一个key时,找当前key值大1的数也存不存在哈希表中,如果存在就相加与当前的max变量进行比较。
    int findLHS(vector<int>& nums) {
        unordered_map<int,int> hash;
        int longest = 0;
        for (int it : nums) {
            hash[it]++;
        }
        for (auto it : hash) {
            if(hash.find(it.first+1) != hash.end()){
                longest = max(longest, it.second + hash[it.first+1]);
            }
        }
        return longest;
    }

独一无二的出现次数

leetcode 给你一个整数数组 arr,请你帮忙统计数组中每个数的出现次数。 如果每个数的出现次数都是独一无二的,就返回 true;否则返回 false。

解题思路

  • 暴力法map + set, 用map记录出现的次数,set判断是否有重复
  • 判断是否有重复可以直接比较set.size() == arr.size()是否相同,相同说明无重复
        bool uniqueOccurrences(vector<int>& arr) {
            map<int, int> cnts;
            for (auto num : arr) {
                cnts[num]++;
            }

            unordered_set<int> set;
            for (auto cnt : cnts) {
                if (set.find(cnt.second) == set.end()) {
                    set.insert(cnt.second);
                } else {
                    return false;
                }
            }
            return true;
        }

O(1)时间插入、删除和获取随机元素-允许重复

leetcode 设计一个支持在平均 时间复杂度 O(1) 下, 执行以下操作的数据结构。 注意: 允许出现重复元素。 insert(val):向集合中插入元素 val。 remove(val):当 val 存在时,从集合中移除一个 val。 getRandom:从现有集合中随机获取一个元素。每个元素被返回的概率应该与其在集合中的数量呈线性相关。

解题思路

    unordered_map<int, unordered_set<int>> idx;
    vector<int> nums;
    RandomizedCollection() {

    }
    
    bool insert(int val) {
        bool res = idx.find(val) == idx.end();
        nums.push_back(val);
        idx[val].insert(nums.size() - 1);
        return res;
    }
    
   bool remove(int val) {
        if (idx.find(val) == idx.end()) {
            return false;
        }
        int i = *(idx[val].begin());    // 取当前数值的下标
        nums[i] = nums.back();          // 与最后一个数替换
        idx[val].erase(i);              // 更新当前数字的下标数组

        idx[nums[i]].erase(nums.size() - 1); // 更新最后一个数的下标数组
        if (i < nums.size() - 1) {
            idx[nums[i]].insert(i);     
        }

        if (idx[val].size() == 0) {     // 删光了 
            idx.erase(val);
        }
        nums.pop_back();        // O(1)删除最后一个数字
        return true;
    }

    int getRandom() {
        return nums[rand() % nums.size()];
    }

两个数组的交集

leetcode 给定两个数组,编写一个函数来计算它们的交集。

示例:

输入:nums1 = [1,2,2,1], nums2 = [2,2]
输出:[2]

解题思路

  • 哈希表记录数组一数字出现次数
  • 遍历数组二,出现过的加入结果
    vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
        unordered_map<int, int> has;
        for (auto num : nums1) {
            has[num]++; 
        }
        unordered_set<int> res;
        for (auto num : nums2) {
            if (has[num] > 0) 
                res.insert(num);
        }
        return vector<int> (res.begin(), res.end());
    }
    vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
        vector<int> res;
        unordered_set<int> set1;
        unordered_set<int> set2;
        for (auto num : nums1) {
            set1.insert(num);
        }
        for (auto num : nums2) {
            set2.insert(num);
        }
        for (auto num : set1) {
            if (set2.find(num) != set2.end()) {
                res.push_back(num);
            }
        }
        return res;
    }

数组的相对排序

leetcode 给你两个数组,arr1 和 arr2, arr2 中的元素各不相同 arr2 中的每个元素都出现在 arr1 中 对 arr1 中的元素进行排序,使 arr1 中项的相对顺序和 arr2 中的相对顺序相同。未在 arr2 中出现过的元素需要按照升序放在 arr1 的末尾。

解题思路

  • 设计排序规则,不在arr2中的数字rank级别最低,在arr2中的数字按下标rank级别比较
    vector<int> relativeSortArray(vector<int>& arr1, vector<int>& arr2) {
        unordered_map<int, int> rank;
        for (int i = 0; i < arr2.size(); ++i) {
            rank[arr2[i]] = i;
        }
        sort(arr1.begin(), arr1.end(), [&](int x, int y){
            if (rank.find(x) != rank.end()) {
                return rank.find(y) != rank.end() ? rank[x] < rank[y] : true;
            } else {
                return rank.find(y) != rank.end() ?  false : x < y;
            }
        });
        return arr1;
    }
  • 暴力法,统计arr1中所有数字出现次数,并记录哪些没有出现在arr2中的数字,然后按照arr2中数字顺序进行输出,最后插入没有出现的数字
    vector<int> relativeSortArray(vector<int>& arr1, vector<int>& arr2) {
        unordered_map<int, int> cnt;
        unordered_set<int> set(arr2.begin(), arr2.end());
        sort(arr1.begin(), arr1.end());

        vector<int> res1;
        for (auto num : arr1) {
            cnt[num]++;
            if (set.find(num) == set.end()) {
                res1.push_back(num);
            }
        }
        vector<int> res2;
        for (auto num : arr2) {
            while (cnt[num]) {
                res2.push_back(num);
                cnt[num]--;
            }
        }
        res2.insert(res2.end(), res1.begin(), res1.end());
        return res2;
    }

四数相加II

leetcode 给定四个包含整数的数组列表 A , B , C , D ,计算有多少个元组 (i, j, k, l) ,使得 A[i] + B[j] + C[k] + D[l] = 0。

输入:
A = [ 1, 2]
B = [-2,-1]
C = [-1, 2]
D = [ 0, 2]
输出:
2
解释:
两个元组如下:
1. (0, 0, 0, 1) -> A[0] + B[0] + C[0] + D[1] = 1 + (-2) + (-1) + 2 = 0
2. (1, 1, 0, 0) -> A[1] + B[1] + C[0] + D[0] = 2 + (-1) + (-1) + 0 = 0

解题思路

  • 用哈希表记录所以A+B的组合之和,再遍历所以C+D之和看有没有相反数,将四数之和变为两数之和
    int fourSumCount(vector<int>& A, vector<int>& B, vector<int>& C, vector<int>& D) {
        unordered_map<int, int> hash;
        for (auto a : A) {
            for (auto b : B) {
                hash[a + b]++;
            }
        }
        int res = 0;
        for (auto c : C) {
            for (auto d : D) {
                res += hash[-c - d];
            }
        }
        return res;
    }
1
https://gitee.com/liuwentao1234/leetcode-note.git
git@gitee.com:liuwentao1234/leetcode-note.git
liuwentao1234
leetcode-note
leetcode-note
master

搜索帮助