哈希表

27 阅读3分钟

哈希表

就我目前的认知而言,我认为map,哈希表,数组三个名词的关系如下

  1. 抽象意义上的map,是键值映射,声明了若干方法如getremove,只定义操作语义,但并无具体实现和复杂度要求
  2. 哈希表是根据关键码的值而直接进行访问的数据结构,核心与数组类似,通过哈希函数将key映射到桶,要求哈希函数的平均复杂度为O(1)并能正确处理碰撞。
  3. 数组是最朴素的哈希表,不需要哈希函数。可视为直接寻址表,是“hash(key)=key”的极端情况,
    是映射结构的受限特例,但不是通用哈希表

[1] 两数之和

给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target  的那 两个 整数,并返回它们的数组下标。

你可以假设每种输入只会对应一个答案,并且你不能使用两次相同的元素。

你可以按任意顺序返回答案。

经典。主要回顾一下api。有两种方法,要弄清楚:

1.找自己需要的 -> 否则记录自己,看看别人需不需要

2.找自己 -> 否则记录自己需要的,看看是不是在后面

vector<int> twoSum(vector<int>& nums, int target) {
    int size = nums.size();
    unordered_map<int,int> map;
    for(int i = 0; i < size; i++){
        //先找自己需要的
        if(map.find(target-nums[i])!=map.end()){
            return {map[target-nums[i]],i};
        }
        else{//找不到 记录自己
            map[nums[i]] = i;
        }
    }
    return {};
}

[49] 字母异位词分组

给你一个字符串数组,请你将 字母异位词 组合在一起。可以按任意顺序返回结果列表。

示例 1:

输入:  strs = ["eat", "tea", "tan", "ate", "nat", "bat"]

输出: [["bat"],["nat","tan"],["ate","eat","tea"]]

解释:

  • 在 strs 中没有字符串可以通过重新排列来形成 "bat"
  • 字符串 "nat" 和 "tan" 是字母异位词,因为它们可以重新排列以形成彼此。
  • 字符串 "ate" ,"eat" 和 "tea" 是字母异位词,因为它们可以重新排列以形成彼此。

异位词等同于所有字母出现次数相同,定义26字节的字符串,每字节记录对应字母出现次数。 以此为key,用链表或数组存相同编码结果的字符串为value。最后,让pair.second加入数组。

class Solution {
public:
    vector<vector<string>> groupAnagrams(vector<string>& strs) {
        //按编码结果分组 key:编码结果 value:相同编码的字符串数组(链表也行)
        unordered_map<string,vector<string>> Code2Group;
        int size = strs.size();
        for(int i = 0; i < size; i++){
            string s = encode(strs[i]);//编码
            Code2Group[s].push_back(strs[i]);//依据编码进行push
        }
        vector<vector<string>> ans;
        for(auto& s_arry : Code2Group){
            ans.push_back(s_arry.second);//拿到的是pair,要取第二个
        }
        return ans;
    }
    //字符串-> 26位编码 处理函数
    string encode(string& s){
        string count(26,'0');
        for(char c : s){
            int index = c -'a';
            count[index]++;
        }
        return count;
    }
};

[128] 最长连续序列

给定一个未排序的整数数组 nums ,找出数字连续的最长序列(不要求序列元素在原数组中连续)的长度。

请你设计并实现时间复杂度为 O(n) **的算法解决此问题。

 

示例 1:

输入: nums = [100,4,200,1,3,2]
输出: 4
解释: 最长数字连续序列是 [1, 2, 3, 4]。它的长度为 4。

只要找出最长序列,不需要连续,也不需要索引,因此让数组加入hash set是最好的方法

虽然是for循环里面套了while,但,while循环遍历的除第一个起始元素外,其余元素均不是开头元素。因此在外层for循环直接continue。一个元素最多被访问两次,故复杂度为O(N)

int longestConsecutive(vector<int>& nums) {
    unordered_set<int> set(nums.begin(),nums.end());//数组加入哈希集合
    int ans = 0;
    for(int num : set){
        if(set.find(num-1)!=set.end()){
            continue; //非起始元素直接进入下次for
        }
        else{
            int currentLength = 0;
            while(set.find(num)!=set.end()){
                num++;
                currentLength++;
            }
            ans = max(ans,currentLength);
        }
    }
    return ans;
}