哈希表_数据结构

哈希表

1.定义:利用散列技术(建立一个对应关系)将记录存储在一块连续的存储空间中,这块连续存储空间称为散列表或者哈希表。
2.性质:
  • 散列技术即是一种存储方法,也是一种查找方法。
  • 数据元素之间没有逻辑关系,不能像其他数据结构利用连线图表示出来。
  • 存储位置和关键字相关联。是一个面向查找的数据存储结构。
3.设计要求:
  • 计算简单,就是建立对应关系的函数应该简洁,并能够防止地址冲突
  • 散列表的地址分布均匀。
4.方法选取:
  • 方法很多:直接定地址法,平方取中法,数字分析法,除留余数法
  • 除留余数法:是最常用的构造散列函数的方法
    \[f(key)=key \ mod\ p (p\leq m),m=length(hash map)\]
5.解决散列冲突问题:
  • 开放定址法:地址一旦冲突,就去寻找下一个空的散列地址。这种方法也叫线性探测法。
    \[f_{i}(key)=(f(key)+d_{i}) \ mod\ m\]
  • 链地址法:一旦出现冲突,原地增加链表,增加结点。
  • 公共溢出法:将所有的冲突值进行溢出,添加一个溢出表,所有冲突值按顺序全部存入溢出表

目录

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;
    }
};

转载于:https://www.cnblogs.com/GeekDanny/p/9802912.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值