哈希表_數據結構


哈希表

1.定義:利用散列技術(建立一個對應關系)將記錄存儲在一塊連續的存儲空間中,這塊連續存儲空間稱為散列表或者哈希表。

2.性質:

  • 散列技術即是一種存儲方法,也是一種查找方法。
  • 數據元素之間沒有邏輯關系,不能像其他數據結構利用連線圖表示出來。
  • 存儲位置和關鍵字相關聯。是一個面向查找的數據存儲結構。

3.設計要求:

  • 計算簡單,就是建立對應關系的函數應該簡潔,並能夠防止地址沖突
  • 散列表的地址分布均勻。

4.方法選取:

  • 方法很多:直接定地址法,平方取中法,數字分析法,除留余數法
  • 除留余數法:是最常用的構造散列函數的方法

\[f(key)=key \ mod\ p (p\leq m),m=length(hash map)$$ <br> #### 5.解決散列沖突問題: - 開放定址法:地址一旦沖突,就去尋找下一個空的散列地址。這種方法也叫線性探測法。 $$f_{i}(key)=(f(key)+d_{i}) \ mod\ m\]

  • 鏈地址法:一旦出現沖突,原地增加鏈表,增加結點。
  • 公共溢出法:將所有的沖突值進行溢出,添加一個溢出表,所有沖突值按順序全部存入溢出表

目錄

  • [347.TOP k frequent elements](#347.TOP k frequent elements)
  • [349.兩個數組的交集](#349. Intersection of Two Arrays)
  • [187.DNA中的重復序列](#187.Repeated DNA Sequences)
  • [205.相同結構的字符串](#205.Isomorphic String)
  • [451.按照頻率排序字符](#451. Sort Characters By Frequency)
  • [500.鍵盤行元素](#500. Keyboard Row)
  • [508.子樹和的出現頻率](#508. Most Frequent Subtree Sum)
  • [389.字符串的不同](#389. Find the Difference)
  • [409.最長的回文字符串](#409. Longest Palindrome)
  • [438.找到所有回文字符串的位置](#438. Find All Anagrams in a String)

349. Intersection of Two Arrays

// unordered_set 哈希表的數據結構的使用
class Solution {
public:
    vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
        vector<int> result;
        unordered_set<int> nums1_set (nums1.begin(),nums1.end());
        for(auto i:nums2){
            if(nums1_set.count(i)){
                result.push_back(i);
                nums1_set.erase(i);
            }
        }
        return result;    
    }
};

347.TOP k frequent elements

# 用了兩種數據結構,一個字典,一個堆排序
from collections import Counter
import heapq
class Solution:
    def topKFrequent(self, nums, k):
        """
        :type nums: List[int]
        :type k: int
        :rtype: List[int]
        """
        
        nums_dict=Counter(nums)
        return heapq.nlargest(k,nums_dict,nums_dict.get)

# 自己寫的,但是不對
from collections import Counter
class Solution:
    def topKFrequent(self, nums, k):
        """
        :type nums: List[int]
        :type k: int
        :rtype: List[int]
        """
        
        nums_dict=Counter(nums)
        a=[]
        for i,v in nums_dict.items(): # 這里估計是缺少排序
            a.append(i)
        return a[0:k]
// c++ 是使用 map哈希和優先隊列來實現
class Solution {
public:
    vector<int> topKFrequent(vector<int>& nums, int k) {
        // 好好學習如何新建一個哈希map
        unordered_map<int,int> map;
        for(int num : nums){
            map[num]++;
        }
        
        vector<int> res;
        // pair<first, second>: first is frequency,  second is number
        priority_queue<pair<int,int>> pq; 
        for(auto it = map.begin(); it != map.end(); it++){
            // 實現對pair,關聯容器還是要看看
            pq.push(make_pair(it->second, it->first));// 注意這個優先隊列的特性,在
            // 插入元素的時候就根據 it->second 的大小值進行排序了。
            if(pq.size() > (int)map.size() - k){
                res.push_back(pq.top().second);
                pq.pop();
            }
        }
        return res;
    }
};

// 同樣的方法
class Solution {
public:
    vector<int> topKFrequent(vector<int>& nums, int k) {
        vector<int> result;
        unordered_map<int,int>nums_map;
        for(int num:nums){
            nums_map[num]++;
        }
        priority_queue<pair<int,int>> pq;
        for(auto it=nums_map.begin(); it!=nums_map.end();it++){
            pq.push(make_pair(it->second,it->first));        
            }
            // 這樣會更好的理解一點
        for(int j=0;j<k;j++){
            result.push_back(pq.top().second);
            pq.pop();
        }
        
        return result;
    }
};

187.Repeated DNA Sequences

// 自己思考的方法,就是最暴力的讀取計數法
// 利用哈希map來存儲個數
class Solution {
public:
    vector<string> findRepeatedDnaSequences(string s) {
        vector<string> result;
        if(s.size()<10)
            return result;
        map<string,int> string_count;
        for(int i=0;i<s.size()-10+1;i++){
            string sub_str=s.substr(i,10);
            string_count[sub_str]++;
        }
        for(const auto &w:string_count){
            if(w.second>1){
                result.push_back(w.first);
            }
        }
        return result;
    }
};

205.Isomorphic String

// 這個是沒有ac的版本
// 主要問題是在建立映射的時候出現了一點問題
class Solution {
public:
    bool isIsomorphic(string s, string t) {
        map<char,char> str_map;
        if(s.size()!=t.size())
            return false;
        for(int i=0;i<s.size();i++){
            if(!str_map.count(t[i]))
                str_map[s[i]]=t[i];
            if(str_map[s[i]]!=t[i])
                return false;
        }
        return true;
    }
};
// 上面整體的解題思路不對
// 利用兩個數組來實現 map映射的關系
class Solution {
public:
    bool isIsomorphic(string s, string t) {
        int num_ss[256]={0}, num_st[256]={0},n=s.size();
        for(int i=0;i<n;i++){
            if(num_ss[s[i]]!=num_st[t[i]])
                return false;
            num_ss[s[i]]=i+1;  //要改變一起改變,要不就不改變
            num_st[t[i]]=i+1;
        }
        return true;
    }
};

451. Sort Characters By Frequency

class Solution {
public:
    string frequencySort(string s) {
        unordered_map<char,int> m;
        string result;
        map<int,vector<char>> m_freq;
        for(auto c:s){
            m[c]++;
        }
        for(auto x:m){
            m_freq[x.second].push_back(x.first);
        }
        for(auto it=m_freq.rbegin();it!=m_freq.rend();it++){ // rbegin() 進行逆序輸出
            // map有的操作,但是unordered_map沒有
            for(auto c:it->second)// 遍歷vector中所有的字符串
                result.append(it->first,c);
        }
        return result;  
    }
};

// 這個解法 有點東西
class Solution {
public:
    string frequencySort(string s) {
        unordered_map<char,int> freq;
        vector<string> bucket(s.size()+1, "");
        string res;
        
        //count frequency of each character
        for(char c:s) freq[c]++;
        //put character into frequency bucket
        for(auto& it:freq) {
            int n = it.second;
            char c = it.first;
            bucket[n].append(n, c); // 這個語句沒看懂
        }
        //form descending sorted string
        for(int i=s.size(); i>0; i--) {
            if(!bucket[i].empty())
                res.append(bucket[i]);
        }
        return res;
    }
};

500. Keyboard Row

// 鍵盤元素
class Solution {
public:
    vector<string> findWords(vector<string>& words) {
        unordered_set<char> row1 {'q', 'w', 'e', 'r', 't', 'y','u', 'i', 'o', 'p'};
        unordered_set<char> row2 {'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l'}; 
        unordered_set<char> row3 { 'z', 'x', 'c', 'v', 'b' ,'n', 'm'};
        vector<unordered_set<char>> rows {row1, row2, row3};
        
        vector<string> result;
        for(int i=0;i<words.size();i++){
            int row=0;
            for(int k=0;k<3;k++){
                if(rows[k].count((char)tolower(words[i][0]))>0)
                    row=k;    
            }
            result.push_back(words[i]);
            for(int j=0;j<words[i].size();j++){
                if(rows[row].count((char)tolower(words[i][j]))==0){
                    result.pop_back();
                    break;
                }   
            }
        }
        return result;    
    }
};

508. Most Frequent Subtree Sum

// 自己想的思路完全正確
// 就是代碼沒能自己實現
//1.自下而上的計算所有結點的 node_subtree_sum1.自下而上的計算所有結點的 node_subtree_sum,並存儲在一個vector中
//2.對vector中的和及其出現的次數建立一個map
//3.輸出出現次數最多的 sum
/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    vector<int> findFrequentTreeSum(TreeNode* root) {
        vector<int>result;
        unordered_map<int,int> counts;
        int max_count=INT_MIN;
        subTreeSum(root,counts,max_count);
        for(auto &x:counts){
            if(x.second==max_count){
                result.push_back(x.first);
            }
        }
        return result;
        
    }
    // 自下而上而上的代碼要多看看,學習
    int subTreeSum(TreeNode *root,unordered_map<int,int>&counts,int &max_count){
        if(!root)
            return 0;
        int sum=root->val;
        sum+=subTreeSum(root->left,counts,max_count);
        sum+=subTreeSum(root->right,counts,max_count);
        counts[sum]++;
        max_count=max(max_count,counts[sum]);
        return sum;
    }
};

389. Find the Difference

// 很簡單的一道題
// 解題思路和205 一樣
// 都是建立一個 數組的hash來實現計數功能
class Solution {
public:
    char findTheDifference(string s, string t) {  
        char temp;
        int cnt[128]={0};
        for(auto &c:s)
            cnt[c]++;
        for(auto &c:t){
            cnt[c]--;
            if(cnt[c]<0)
                return c;
        }
        return temp;     
    }
};

409. Longest Palindrome

// 自己寫的版本
class Solution {
public:
    int longestPalindrome(string s) {
        int max_length=0;
        map<char,int> m;
        for(auto &c:s){
            m[c]++;
        }
        for(const auto w:m){
            if(w.second!=1)
                max_length+=w.second;
        }
        return max_length+1;
    }
};
//能用 vector就用 vector
// 一到字符串這塊就歇逼,哎
class Solution {
public:
    int longestPalindrome(string s) {
        vector<int> m(256, 0);        
        for (auto& c : s) m[c-'\0']++;
        int result = 0;
        for (auto& i : m) result += i%2 ? (result%2 ? i-1 : i) : i;
        return result;
    }
};

438. Find All Anagrams in a String

class Solution {
public:
    vector<int> findAnagrams(string s, string p) {
        vector<int> pv(26,0), sv(26,0), res;
        if(s.size() < p.size())
           return res;
        // fill pv, vector of counters for pattern string and sv, vector of counters for the sliding window
        for(int i = 0; i < p.size(); ++i)
        {
            ++pv[p[i]-'a'];
            ++sv[s[i]-'a'];
        }
        if(pv == sv)
           res.push_back(0);

        //here window is moving from left to right across the string. 
        //window size is p.size(), so s.size()-p.size() moves are made 
        for(int i = p.size(); i < s.size(); ++i) 
        {
             // window extends one step to the right. counter for s[i] is incremented 
            ++sv[s[i]-'a'];
            
            // since we added one element to the right, 
            // one element to the left should be forgotten. 
            //counter for s[i-p.size()] is decremented
            --sv[s[i-p.size()]-'a']; 

            // if after move to the right the anagram can be composed, 
            // add new position of window's left point to the result 
            if(pv == sv)  
               res.push_back(i-p.size()+1);
        }
        return res;
    }
};


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM