第六天|LeetCode: 哈希表理论基础 242.有效的字母异位词 349. 两个数组的交集 202. 快乐数 1. 两数之和

哈希表理论知识

代码随想录讲解

1.哈希表用来解决什么问题

一般哈希表都是用来快速判断一个元素是否出现集合里。

2.常见的三种哈希结构

  • 数组
  • set (集合)
  • map(映射)
集合 底层实现 是否有序 数值是否可以重复 能否更改数值 查询效率 增删效率
std::set 红黑树 有序 O(log n) O(log n)
std::multiset 红黑树 有序 O(logn) O(logn)
std::unordered_set 哈希表 无序 O(1) O(1)

std::unordered_set底层实现为哈希表,std::set 和std::multiset 的底层实现是红黑树,红黑树是一种平衡二叉搜索树,所以key值是有序的,但key不可以修改,改动key值会导致整棵树的错乱,所以只能删除和增加。

映射 底层实现 是否有序 数值是否可以重复 能否更改数值 查询效率 增删效率
std::map 红黑树 key有序 key不可重复 key不可修改 O(logn) O(logn)
std::multimap 红黑树 key有序 key可重复 key不可修改 O(log n) O(log n)
std::unordered_map 哈希表 key无序 key不可重复 key不可修改 O(1) O(1)

std::unordered_map 底层实现为哈希表,std::map 和std::multimap 的底层实现是红黑树。同理,std::map 和std::multimap 的key也是有序的(这个问题也经常作为面试题,考察对语言容器底层的理解)。

3.适用场景

数组:存一个数据或可以存多个数据,如字母的异位单词,相当下标存了元素,而值存出没出现过,相当于set,又如赎金信,下标存数据,里面的值存数组个数,相当于map

效率高,但适用于范围小,所以数组包含了他们两个,如果元素很分散就也不能用数组,如果元素不分散,像后面存字母这种,就用数组

set:存一个数据,unordered_set效率高,一般用它,当要有序时用set,有重复元素时用multiset

map:存两个数据,和上面一样,一般用pair存数据



题目链接:242. 有效的字母异位词

c++代码(数组):

class Solution {
public:
    bool isAnagram(string s, string t) {
        int record[26] = {0};
        for (int i = 0; i < s.size(); i++) {
            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) {
                return false;
            }
        }
        return true;
    }
};

思路

判断两个字符串里的元素组成是否相同,

暴力解法两层for循环,判断每个数是否在另一个集合中出现过

所以我们可以用哈希表来做

1.因为数据很小,且允许重复,用数组

2,因为需要把每个数都映射到数组中,有26个字母,所以可以开一个26空间的大小的数组来储存数据,有重复的数据,在那个位置上++

3.最后遍历第二个数组,出现了相同数字,就--

4.如果最后数组还是为0,就是正确的

代码

字符怎么变数字

t[i] - 'a'



题目链接:349. 两个数组的交集

c++代码(set)

class Solution {
public:
    vector intersection(vector& nums1, vector& nums2) {
        unordered_set result_set;
        unordered_set nums_set(nums1.begin(), nums1.end());
        for (int i = 0; i < nums2.size(); i++) {
            if ( nums_set.find(nums2[i]) != nums_set.end()) {
                result_set.insert(nums2[i]);
            }
        } 
           return vector(result_set.begin(), result_set.end());
    }
};

思路

求两个数组的交集

暴力做法:两层for循环判断每个元素是否在另一个数组中,是则加入到一个新数组中,返回新数组

1.判断每个元素是否在另一个数组中可以看出用hash表

2.这题改了,因为数据过大一般用set类型,因为是无序的和去重,用unordered_set

3.把第一个数组中的元素加入一个set中,遍历第二个元素,如果出现的话,就加入新数组

4.返回新数组

代码

        unordered_set nums_set(nums1.begin(), nums1.end());
  • 把一个数组中的元素无序插入一个set中
        for (int i = 0; i < nums2.size(); i++) {
            if ( nums_set.find(nums2[i]) != nums_set.end()) {
                result_set.insert(nums2[i]);
            }
        } 
  • 查找有没有nums2[i]那个元素,如果没到末尾,相当于查询到了那个元素,就加入到结果数组中
  return vector(result_set.begin(), result_set.end());
  • 把set集合中的元素放到数组(容器)中


题目链接:202. 快乐数

c++代码(set)

class Solution {
public:
   int getSum (int x) {
       int sum = 0; 
       while (x > 0) {
           int t = x / 10;
           sum += (x%10) * (x%10);
           x = t;
       }
       return sum;
   }

    bool isHappy(int n) {
         unordered_setresult;
         result.insert(n);
        while (1) {
            int t = getSum(n); 
              if (t == 1) {
                return true;
            }
            if  (result.find(t) != result.end()) {
                return false;
            } else {
                result.insert(n);
            }

            n = t;
         }

    }
};

思路

示例:

输入:19
输出:true
解释:
1^2 + 9^2 = 82
8^2 + 2^2 = 68
6^2 + 8^2 = 100
1^2 + 0^2 + 0^2 = 1

由此可以看出求出最后是否和是否等于1,每次出现的求和数前面一定没有出现过,不然一定会陷入死循环

1.判断一个数是否出现过由此可以看出需要使用哈希法

2.因为范围1 <= n <= 231 - 1且不需要重复元素,还是无序的,用unordered_set

3.可以从第一个数不断求和,如果没出现过这个数就加入到set中,出现过就死循环返回false

4.当求和结果为1,就返回true

代码

            if  (result.find(t) != result.end()) {
                return false;
            } else {
                result.insert(n);
            }

  • 如果查询t在没到set末尾,就说明出现过,返回false,否则插入n进去


题目链接:1. 两数之和

c++代码(map)

class Solution {
public:
    vector twoSum(vector& nums, int target) {
        unordered_map  result;
        for (int i = 0; i < nums.size(); i++) {
            auto val = result.find(target - nums[i]);
            if ( val != result.end()) {
                return {val->second, i};
            }
            result.insert(pair(nums[i], i));
        }
        return {};
    }
};

思路

寻找数组中两个元素,如果相加为目标值,就返回这两个元素的下表

遍历这个数组,如果这个数组中这个元素的互补值在前面出现过,添加到map中了,就找到了

1.查看元素有没有出现过用哈希表,因为储存两个元素(值和下标),用map,无序且效率用unordered_map

2.遍历数组,查元素的互补值,如果这个互补值在前面出现过就找到

3.如果没出现过,就把这个元素加入到map中,继续遍历数组,找不到返回空map

代码

   auto val = result.find(target - nums[i]);
            if ( val != result.end()) {
                return {val->second, i};
            }
            result.insert(pair(nums[i], i));
  •  查找前面出现过了那个值没有,如果有就返回,没有就加入map

你可能感兴趣的:(代码随想录一刷,leetcode,散列表,数据结构,算法,哈希算法)