代码随想录训练营第六天 | 题242 题349 题202

1.哈希表 Hash table

https://programmercarl.com/%E5%93%88%E5%B8%8C%E8%A1%A8%E7%90%86%E8%AE%BA%E5%9F%BA%E7%A1%80.html

当我们要快速判断一个元素是否出现在集合里的时候,就要考虑哈希法。

定义:哈希表是根据关键码的值而直接进行访问的数据结构。如数组。

1.1 哈希函数

把值映射到哈希表的索引上。

如想知道某学生是否存在学校里,首先先将全校学生名字存在哈希表里。通过hashcode把名字转为数值,hashcode是通过特定编码方式将不同数据格式转化成不同数值。将这个数字再对哈希表的大小取模,即为下标。而当学生数量大于哈希表大小时,就会发生哈希碰撞

代码随想录训练营第六天 | 题242 题349 题202_第1张图片

比如两个学生映射到同一个下标,解决方法有拉链法和线性探测法。

拉链法:碰撞的位置创建链表存储多余的元素。

线性探测法:选一个放入碰撞的下标,其余元素往下找空位。tabelsize>datasize

2 有效的字母异位词 LeetCode 题242

给定两个字符串 s 和 t ,编写一个函数来判断 t 是否是 s 的字母异位词。

注意:若 s 和 t 中每个字符出现的次数都相同,则称 s 和 t 互为字母异位词。

来源:力扣(LeetCode)
https://programmercarl.com/0242.%E6%9C%89%E6%95%88%E7%9A%84%E5%AD%97%E6%AF%8D%E5%BC%82%E4%BD%8D%E8%AF%8D.html#%E6%80%9D%E8%B7%AF

此处注意recode[s[i]-‘a’]运用了哈希表的定义,字符转成了下标。

class Solution {
public:
    bool isAnagram(string s, string t) {
        int record[26] = {0};
        for (int i = 0; i < s.size(); i++) {
            // 并不需要记住字符a的ASCII,只要求出一个相对数值就可以了
            record[s[i] - 'a']++;
        }
        for (int i = 0; i < t.size(); i++) {
            record[t[i] - 'a']--;
        }
        for (int i = 0; i < 26; i++) {
            if (record[i] != 0) {
                // record数组如果有的元素不为零0,说明字符串s和t 一定是谁多了字符或者谁少了字符。
                return false;
            }
        }
        // record数组所有元素都为零0,说明字符串s和t是字母异位词
        return true;
    }
};

3.两个数组的交集 LeetCode 题 349

给定两个数组 nums1 和 nums2 ,返回 它们的交集 。输出结果中的每个元素一定是 唯一 的。我们可以 不考虑输出结果的顺序 。

https://programmercarl.com/0349.%E4%B8%A4%E4%B8%AA%E6%95%B0%E7%BB%84%E7%9A%84%E4%BA%A4%E9%9B%86.html#_349-%E4%B8%A4%E4%B8%AA%E6%95%B0%E7%BB%84%E7%9A%84%E4%BA%A4%E9%9B%86

当我们要快速判断一个元素是否出现在集合里的时候,就要考虑哈希法。而用什么结构的哈希法,如果哈希值比较少,特别分散,跨度很大,使用数组类型的哈希表就比较浪费空间。此时可以用set结构体。

对于set,C++中有std::set 、std::multiset、std::unordered。

前两个底层实现是红黑树,后一个是哈希表。输出可以不按顺序,故采用std::unordered_set实现。

if (num_set.find(num) != num_set.end()) 查找num是否在num_set里。

class Solution {
public:
    vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
        unordered_set<int> result_set; // 存放结果,之所以用set是为了给结果集去重
        unordered_set<int> nums_set(nums1.begin(), nums1.end());
        for (int num : nums2) {
            // 发现nums2的元素 在nums_set里又出现过
            if (nums_set.find(num) != nums_set.end()) {
                result_set.insert(num);
            }
        }
        return vector<int>(result_set.begin(), result_set.end());
    }
};

4 快乐数 LeetCode 题202

https://programmercarl.com/0202.%E5%BF%AB%E4%B9%90%E6%95%B0.html

「快乐数」 定义为:

对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和。
然后重复这个过程直到这个数变为 1,也可能是 无限循环 但始终变不到 1。
如果这个过程 结果为 1,那么这个数就是快乐数。
如果 n 是 快乐数 就返回 true ;不是,则返回 false 。

输入:n = 19
输出:true
解释:
12 + 92 = 82
82 + 22 = 68
62 + 82 = 100
12 + 02 + 02 = 1

分析:题目说会无限循环也就是说有个sum重复出现了,以至于第二轮循环继续求该快乐数。判断元素是否出现在集合里(其实也相当于判断元素是否重复),用哈希法。判断sum是否重复出现就可以使用unordered_set。取个位数的操作要详记。

class Solution {
public:
    // 取数值各个位上的单数之和
    int getSum(int n) {
        int sum = 0;
        while (n) {
            sum += (n % 10) * (n % 10);
            n /= 10;
        }
        return sum;
    }
    bool isHappy(int n) {
        unordered_set<int> set;
        while(1) {
            int sum = getSum(n);
            if (sum == 1) {
                return true;
            }
            // 如果这个sum曾经出现过,说明已经陷入了无限循环了,立刻return false
            if (set.find(sum) != set.end()) {
                return false;
            } else {
                set.insert(sum);
            }
            n = sum;
        }
    }
};

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