哈希表习题整理(1)

哈希表模板(来自acwing算法基础课)

1.拉链法
int h[N], e[N], ne[N], idx;

    // 向哈希表中插入一个数
    void insert(int x)
    {
     
        int k = (x % N + N) % N;
        e[idx] = x;
        ne[idx] = h[k];
        h[k] = idx ++ ;
    }

    // 在哈希表中查询某个数是否存在
    bool find(int x)
    {
     
        int k = (x % N + N) % N;
        for (int i = h[k]; i != -1; i = ne[i])
            if (e[i] == x)
                return true;

        return false;
    }

开放寻址法

int h[N];

    // 如果x在哈希表中,返回x的下标;如果x不在哈希表中,返回x应该插入的位置
    int find(int x)
    {
     
        int t = (x % N + N) % N;
        while (h[t] != null && h[t] != x)
        {
     
            t ++ ;
            if (t == N) t = 0;
        }
        return t;
    }

模板题1AcWing840. 模拟散列表

#include 
using namespace std;

const int N = 200003;
const int null = 0x7f7f7f7f;
int h[N];
int find(int x){
     
    int k = (x%N + N) % N;
    while(h[k] != null && h[k] != x){
     
        k = (k+1) % N;
    }
    return k;
}
int main(){
     
    memset(h, 0x7f, sizeof(h));
    int n, x;
    scanf("%d", &n);
    char op[2];
    while(n--){
     
        scanf("%s %d", op, &x);
        if(*op == 'I'){
     
            h[find(x)] = x;
        }
        else if(*op == 'Q'){
     
            if(h[find(x)] == null) puts("No");
            else puts("Yes");
        }
    }
}

模板题2LeetCode706. 设计哈希映射

class MyHashMap {
     
public:
    /** Initialize your data structure here. */
    const int N = 20007;
    typedef pair<int, int> PII;
    vector<list<PII>> hash;

    list<pair<int,int>>::iterator find(int key)
    {
     
        int t = key % N;
        auto it = hash[t].begin();
        for (; it != hash[t].end(); it ++ )
            if (it->first == key)
                break;
        return it;
    }


    MyHashMap() {
     
        hash.resize(N);
    }


    /** value will always be non-negative. */
    void put(int key, int value) {
     
        int t = key % N;
        auto it  = find(key);
        if(it == hash[t].end())
            hash[t].push_back({
     key, value});
        else it->second  = value;
    }
    
    /** Returns the value to which the specified key is mapped, or -1 if this map contains no mapping for the key */
    int get(int key) {
     
        int t = key % N;
        auto it = find(key);
        if(it == hash[t].end()) return -1;
        else return it->second;
    }
    
    /** Removes the mapping of the specified value key if this map contains a mapping for the key */
    void remove(int key) {
     
        int t = key % N;
        auto it = find(key);
        if(it == hash[t].end()) return ;
        else hash[t].erase(it);
    }
};

/**
 * Your MyHashMap object will be instantiated and called as such:
 * MyHashMap* obj = new MyHashMap();
 * obj->put(key,value);
 * int param_2 = obj->get(key);
 * obj->remove(key);
 */

习题1. LeetCode652. 寻找重复的子树

解法一:用先序遍历将二叉树线索化,则每一棵子树对应一个字符串,用hash来记录每条字符串的个数。由于线索化字符串的长度是O(n)的,一共n个节点,做n次操作时间复杂度就成O(n^2)的了。
class Solution {
     
public:
    vector<TreeNode*> ans;
    unordered_map<string, int> hash;

    string dfs(TreeNode* root){
     
        if(!root) return "#";
        auto lt = dfs(root->left);
        auto rt = dfs(root->right);
        string t = to_string(root->val) + "," + lt + "," + rt;
        hash[t] ++;
        if(hash[t] == 2) ans.push_back(root);
        return t; 
    }

    vector<TreeNode*> findDuplicateSubtrees(TreeNode* root) {
     
        dfs(root);
        return ans;
    }
};
解法二:在解法一的基础上可考虑将每一个字符串映射成一个数字,则一棵子树的字符串长度即变成O(1)级的,包括头节点,左边字符串对应的数字,右边字符串对应的数字。时间复杂度降为O(n)级。
class Solution {
     
public:
    int id;
    vector<TreeNode*> ans;
    unordered_map<string, int> tree;
    unordered_map<int, int> hash;

    int dfs(TreeNode* root){
     
        //空串对应id为0
        if(!root) return 0;
        int lt = dfs(root->left);
        int rt = dfs(root->right);
        string t = to_string(root->val) + "," + to_string(lt) + "," + to_string(rt);
        //如果该子树的字符串不存在,则为其分配一个id号
        if(!tree.count(t)) tree[t] = ++id;
        int res = tree[t];
        hash[res] ++; 
        if(hash[res] == 2) ans.push_back(root);
        return res; 
    }

    vector<TreeNode*> findDuplicateSubtrees(TreeNode* root) {
     
        //空串对应id为0
        tree["#"] = id;
        dfs(root);
        return ans;
    }
};

习题2. LeetCode560. 和为K的子数组

思路:使用sum存储前缀和s[i]。mp[sum-k]表示sum-k这一前缀和出现的次数。此时前缀和为sum,sum - (sum - k)即为k,存在mp[sum-k]个子数组和为k。
class Solution {
     
public:
    int subarraySum(vector<int>& nums, int k) {
     
        unordered_map<int, int> mp;
        mp[0] = 1;
        int ans = 0;
        for(int i = 0, sum = 0; i < nums.size(); i ++){
     
            sum += nums[i];
            ans += mp[sum-k];
            mp[sum] ++;
        }
        return ans;
    }
};

你可能感兴趣的:(哈希表,hash,算法)