代码随想录算法训练营day6 | 哈希表理论基础 、 242.有效的字母异位词 、349. 两个数组的交集 、202. 快乐数 、 1. 两数之和

学习目标:

做完四道算法题,并根据视频和文章巩固哈希表理论基础


学习时间:

  • 晚上七点-晚上十点

哈希表理论基础 

文章链接

建议:大家要了解哈希表的内部实现原理,哈希函数,哈希碰撞,以及常见哈希表的区别,数组,set 和map。  

什么时候想到用哈希法,当我们遇到了要快速判断一个元素是否出现集合里的时候,就要考虑哈希法。  这句话很重要,大家在做哈希表题目都要思考这句话。 


242.有效的字母异位词

题目链接/文章讲解/视频讲解

建议: 这道题目,大家可以感受到 数组 用来做哈希表 给我们带来的遍历之处

思路:数组其实就是一个简单哈希表,而且这道题目中字符串只有小写字符,那么就可以定义一个数组,来记录字符串s里字符出现的次数。

操作动画如下:

 代码实现

 var isAnagram = function (s, t) {
      if (s.length !== t.length) {
        return false
      }
      let record = new Array(26).fill(0)
      const base = "a".charCodeAt()
      for (const i of s) {

        record[i.charCodeAt() - base]++
      }
      for (const j of t) {
        if (!record[j.charCodeAt() - base]) {
          return false
        }
        record[j.charCodeAt() - base]--
      }
      return true
    }

349. 两个数组的交集 

题目链接/文章讲解/视频讲解

建议:本题就开始考虑 什么时候用set 什么时候用数组,本题其实是使用set的好题,但是后来力扣改了题目描述和 测试用例,添加了 0 <= nums1[i], nums2[i] <= 1000 条件,所以使用数组也可以了,不过建议大家忽略这个条件。 尝试去使用set。 

思路

这道题目,主要要学会使用一种哈希数据结构:unordered_set,这个数据结构可以解决很多类似的问题。注意题目特意说明:输出结果中的每个元素一定是唯一的,也就是说输出的结果的去重的, 同时可以不考虑输出结果的顺序

这道题用暴力的解法时间复杂度是O(n^2),那来看看使用哈希法进一步优化。

那么用数组来做哈希表也是不错的选择,例如242. 有效的字母异位词(opens new window)

但是要注意,使用数组来做哈希的题目,是因为题目都限制了数值的大小。

而这道题目没有限制数值的大小,就无法使用数组来做哈希表了。

而且如果哈希值比较少、特别分散、跨度非常大,使用数组就造成空间的极大浪费。

此时就要使用另一种结构体了,set 

代码实现

 var intersection = function (nums1, nums2) {
      if (nums1.length < nums2.length) {
        const num1 = nums1
        nums1 = nums2
        nums2 = num1

      }
      const nums1Set = new Set(nums1)
      const resSet = new Set();
      for (let i = 0; i < nums2.length; i++) {
        nums1Set.has(nums2[i]) && resSet.add(nums2[i])
      }
      return Array.from(resSet)
    }

202. 快乐数

题目链接/文章讲解

思路:

所以这道题目使用哈希法,来判断这个sum是否重复出现,如果重复了就是return false, 否则一直找到sum为1为止。

判断sum是否重复出现就可以使用unordered_set。

还有一个难点就是求和的过程,如果对取数值各个位上的单数操作不熟悉的话,做这道题也会比较艰难。

代码实现:

    var isHappy1 = function (n) {
      let record = new Map()
      const getSum = (num) => {
        let sum = 0;
        while (n) {
          sum += (n % 10) ** 2
          n = Math.floor(n / 10)
        }
        return sum
      }
      while (true) {
        if (record.has(n)) {
          return false
        }
        if (n === 1) {
          return true

        }
        record.set(n, 1)

        n = getSum(n)
      }

    }

1. 两数之和 

题目链接/文章讲解/视频讲解

建议:本题虽然是 力扣第一题,但是还是挺难的,也是 代码随想录中 数组,set之后,使用map解决哈希问题的第一题。 

思路:

首先我在强调一下 什么时候使用哈希法,当我们需要查询一个元素是否出现过,或者一个元素是否在集合里的时候,就要第一时间想到哈希法。

本题呢,我就需要一个集合来存放我们遍历过的元素,然后在遍历数组的时候去询问这个集合,某元素是否遍历过,也就是 是否出现在这个集合。

那么我们就应该想到使用哈希法了。

因为本地,我们不仅要知道元素有没有遍历过,还有知道这个元素对应的下标,需要使用 key value结构来存放,key来存元素,value来存下标,那么使用map正合适

代码实现:

    var twoSum = function (nums, target) {
      let map = new Map()
      for (let i = 0; i < nums.length; i++) {
        let s = target - nums[i]
        const iter = map.get(s)
        if (iter !== undefined) {
          return [map.get(s), i]
        }
        map.set(nums[i], i)
      }
      return {}
    }

总结:

总的来说哈希表的学习难度并不高,但是基础原理和使用环境需要弄清楚,尤其是数组、set和map的使用环境

使用数组和set来做哈希法的局限。

  • 数组的大小是受限制的,而且如果元素很少,而哈希值太大会造成内存空间的浪费。
  • set是一个集合,里面放的元素只能是一个key

需要保存key和value的时候需要用到map

继续努力 加油!

你可能感兴趣的:(散列表,数据结构)