开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第10天,点击查看活动详情
前言
本系列文章主要会总结一些常见的算法题目以及算法的易错点,难点,以及一些万用的公式,并且结合实际的 Leetcode 题目来进行加深理解以及实际应用,算法这种东西,属于是一到用时方恨少的类型,在平时总结一些常见的简单算法,经常磨练自己的算法思维,对于日常的开发还是能有不少的帮助的。
- 今天来简单介绍一下哈希表的基础知识以及做一道简单的应用题.
哈希表是什么
首先什么是 哈希表
哈希表就是一种以 键-值(key-value) 存储数据的结构,我们只要输入待查找的值即key,即可查找到其对应的值。
这么这官方的解释可能有点懵,其实日常当中最常见的数组就是一张哈希表
哈希表中关键码就是数组的索引下标,然后通过下标直接访问数组中的元素,如下图所示:
在数组 ['a','b','c','d','e'] 中每个下标分别就会对应一个元素,这就是一张哈希表,通过下标这个 key 来匹配实际的 value。
那么哈希表能解决什么问题呢,一般哈希表都是用来快速判断一个元素是否出现集合里。
例如要查询一个同学是否存在一个班级当中,如果通过循环枚举的话,那就需要 O(n) 的时间复杂度,但是要是使用哈希表的话,只需要 O(1) 的时间复杂度就可以做到了。
只需要在初始化的时候把班级中的学生都保存到哈希表当中去,查询的时候通过需要查询的学生就可以查到,这个学生是否存在这张哈希表当中,这样就可以最快的查找到。
在js当中,常见的哈希表有 数组 对象 map(映射) 以及 set(集合)
什么是哈希函数
哈希函数指将哈希表中元素的关键键值映射为元素存储位置的函数。
比如上面的班级哈希表,那么将班级同学列表映射到哈希表中的函数,就叫哈希函数。
比方说同学一名字叫做小王,同学二名字叫做小明,哈希函数可以根据每个人名字或者其他特征生成一个key,并且在哈希表中这个key就对应了这个人。
那么一旦人比较多,难以避免的就是哈希表的key发生了重复,有两笔数据被映射到了同一个key上面,这时候就是发生了哈希碰撞
哈希碰撞
比如刚好小王和小明得到的key都是0,那么都映射到了下标为0的这个位置,这时候就发生了 哈希碰撞
所以说哈希函数的设计是很重要的,好的哈希函数能够尽可能的保证计算简单和分布均匀。
关于哈希冲突的介绍就到这边结束,解决方法之后要是碰到再来详细展开。
Leetcode 242.有效的字母异位词
给定两个字符串 s 和 t ,编写一个函数来判断 t 是否是 s 的字母异位词。
注意:若 s 和 t 中每个字符出现的次数都相同,则称 s 和 t 互为字母异位词。
暴力解法
暴力解法没什么好说的,双重循环两个字符串,然后去记录下每一个字符是否在第一个出现第二个也出现,记录下出现的一个次数,这样的时间复杂度很明显的来到了 O(n2)
那么我们就用哈希表来进行优化,将时间复杂度降低为 O(n)
哈希表
在前面我们提到了,其实数组就是一张哈希表,key为数组下标,value为数组的值。
题目只要求计算小写字母,所以我们可以初始化大小为26的数组,每一个位置对应这个字母的出现次数,在遍历第一个字符串的时候在对应的位置递增,在遍历第二个字符串的时候,在对应的位置递减,最后这个数组的每一位都为0的话,就说明两个字符串为字母异位词。
这样子只需要遍历两个字符串,以及一遍数组,将时间复杂度将为了 O(n)。
这里提一下js的两个数组方法 -- some 和 every
两个函数都是遍历数组并且去判断是否满足某些条件,不同的点在于some相当于逻辑关系中的或,只要有一个参数满足条件,则中断遍历,返回true,如果遍历完所有参数,没有找到符合的项,即返回false;every相当于关系中的且,只有所有关系都满足条件时才返回true,一旦有一个不满足,则中断遍历,返回fasle。
let arr = [7, 6, 5, 4, 3, 2, 1];
console.log(arr.some((item, index) => {
return item > 6 // 返回true
}));
console.log(arr.every((item, index) => {
return + item > 6 // 返回 false
}));
那么这道题最后,我们可以使用这两个函数来判断数组是否满足都为 0。
function isAnagram(s: string, t: string): boolean {
if (s.length !== t.length) return false;
let arr: number[] = new Array(26).fill(0);
let aCode: number = 'a'.charCodeAt(0);
for (let i = 0; i < s.length; i++) {
arr[s.charCodeAt(i) - aCode]++;
arr[t.charCodeAt(i) - aCode]--;
}
return arr.every(i => i === 0);
};