力扣: 哈希表 查找共用字符

138 阅读4分钟

哈希表

概念

哈希表也叫作散列表,是根据关键码值(key)而直接进行访问的数据结构,也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度。这个映射函数叫做散列函数,存放记录的数组叫做散列表.

散列表

我们先来认识一下一下散列表:

在记录的存储位置与该记录的关键值中间建立一种确定的对应关系,并使得每个记录的关键字值与结构中的一个唯一的储存位置相对应。这个关系会记录与当前关键字key相关的函数,也就是散列函数。只要根据这个对应关系就可以找到所要找到的记录。由于可能不同的关键字会得到相同的值,所以会造成散列冲突。我们分析题目就是要分析冲突的现象。

有以下几种构造方法

直接定址法

直接取关键字的某个函数作为散列函数,即H(k) = ak + b。其中,a , b 为常量,k为自变量

数字分析法

当关键字值的位数大于散列地址码的位数时,对关键字值的各个数字进行分析,从中取出和散列地址位数相同的数

平方取中法

计算关键值的平方,有目的的选取若干位作为散列地址

叠加法

移位叠加法和折叠叠加法

基数转换法

关键字值原来为十进制数,人为地当做q进制数,再转换成十进制作为散列地址

除留余数法

也就是取模法:对应的散列函数为H(k) = k MOD p。这个使用范围是最广的,也是最常用的构造散列函数的方法

随机数法

即产生一定范围内的随机数,散列函数为H(k) = random(k).random()为随机函数。

例题

看了这么多哈希表的知识,我们先来一道简单的题目。

给你一个字符串数组 words ,请你找出所有在 words 的每个字符串中都出现的共用字符( 包括重复字符),并以数组形式返回。你可以按 任意顺序 返回答案。

示例

输入:words = ["bella","label","roller"]
输出:["e","l","l"]

题目分析

题目中表明需要在world数组中各个字符串之间都出现的公共字符。有的人就直接会想,我直接遍历不就好了吗,每个字符串遍历一下,找个公共字符串还不简单吗?显然这样子的代码不高效,且对于字符串的多种情况也不适用。而这里无疑是考虑字符出现的个数,也就是频率,所以我们这里考虑使用哈希表。而我们构造的哈希函数就是对应的26个字母。那么我们就定义一个hash[]数组,先统计第一个字符串出现的字符,使其加一,而这里我们使用ASCI码分别来为字符串中出现的字母统计次数。然后再定义另外一个hash1表,来统计其余字符串的字母出现情况,两表相互比对,最后再输出相同的hash表中内容就行。

class Solution {
public:
    vector<string> commonChars(vector<string>& A) {
        vector<string> result;
        if (A.size() == 0) return result;
        int hash[26] = {0};             // 整合另外一个哈希表,作为输出结果
        for (int i = 0; i < A[0].size(); i++) { // 标记第一个字符串的字母情况
            hash[A[0][i] - 'a']++;
        }

        int hash1[26] = {0}; //   统计其余字符串外字符的出现频率
        for (int i = 1; i < A.size(); i++) {
            memset(hash1, 0, 26 * sizeof(int));
            for (int j = 0; j < A[i].size(); j++) {
                hashOtherStr[A[i][j] - 'a']++;
            }
            // 及时更新hash,以免影响后续的统计
            for (int k = 0; k < 26; k++) {
                hash[k] = min(hash[k], hash1[k]);
            }
        }
        // 将hash统计的字符次数,转成输出形式
        for (int i = 0; i < 26; i++) {
            while (hash[i] != 0) { // 注意这里是while,多个重复的字符
                string s(1, i + 'a'); // char -> string
                result.push_back(s);
                hash[i]--;
            }
        }
        return result;
    }
};

代码分析

这里我们用ASCII码来计算,利用字母减a的哈希函数来建立我们的字母与hash数组中出现的频率的关系。这里需要注意的是每次比对完一个字符串后,我们都需要及时更新hash表中的内容,也就是这行hash[k] = min(hash[k], hash1[k],以免影响后续的统计。依次进行比对后,最后再把hash表中值为一的地方,也就是共同字母,之后转换为字母输出。

总结

这次的题目还是比较简单的,情况也不是很复杂,初次试水哈希表,接触的也不是很难,后续还会讲解更难的题目,个人觉得我还要努力提升自我,代码之路还长,得慢慢走!

希望感兴趣的小伙伴一起学习,谢谢!