day9 哈希表 |有效的字母异位词|两个数组的交集|快乐数|两数之和

代码随想录

哈希表(散列表):

根据关键码的值而直接进行访问的数据结构。

数组其实就是一张哈希表

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

哈希函数

把学生的姓名直接映射为哈希表上的索引

通过hashCode把名字转化为数值,一般hashcode是通过特定编码方式,可以将其他数据格式转化为不同的数值,这样就把学生名字映射为哈希表上的索引数字了。

index = hashFunction(name)

hashFunction = hashcode(name)%tableSize

如果hashCode得到的数值大于 哈希表的大小了,也就是大于tableSize了,怎么办呢?

取模

如果学生的数量大于哈希表的大小怎么办,此时就算哈希函数计算的再均匀,也避免不了会有几位学生的名字同时映射到哈希表 同一个索引下标的位置。

哈希碰撞

小李和小王都映射到了索引下标 1 的位置,这一现象叫做哈希碰撞

一般哈希碰撞有两种解决方法, 拉链法和线性探测法。

#拉链法

刚刚小李和小王在索引1的位置发生了冲突,发生冲突的元素都被存储在链表中。 这样我们就可以通过索引找到小李和小王了

其实拉链法就是要选择适当的哈希表的大小,这样既不会因为数组空值而浪费大量内存,也不会因为链表太长而在查找上浪费太多时间。

线性探测法

数据规模是dataSize, 哈希表的大小为tableSize

使用线性探测法,一定要保证tableSize大于dataSize。 我们需要依靠哈希表中的空位来解决碰撞问题。

例如冲突的位置,放了小李,那么就向下找一个空位放置小王的信息。所以要求tableSize一定要大于dataSize ,要不然哈希表上就没有空置的位置来存放 冲突的数据了。

常见的三种哈希结构

当我们想使用哈希表来解决问题的时时候

我们一般会选择如下三种结构

数组

set(集合)

map(映射)

总结

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

但是哈希表牺牲了空间来换取时间

因为我们要使用额外的数组,set或者是map来存放数据,才能实现快速的查找。

有效的字母异位词

// /**
//  * @param {string} s
//  * @param {string} t
//  * @return {boolean}
//  */
// var isAnagram = function(s, t) {
// // 用哈希表怎么解决 数组其实就是一个简单的哈希表
// // 其实我之前用过,只是当时不知道它是哈希表
// // 用一个数组记录s中每个字符出现的次数
// // 需要把字符映射到数组也就是哈希表的索引下标下 
// // 因为字符a到z的ASCII是26个连续的数值,所以把a字符映射为0 ,z 25 ‘b/c/d’-'a' 

// // 对于 s +1  t -1 最后只有0 符合
// // 怎么定义

// const record = new Array(26).fill(0)

// for(let i=0;i<s.length;i++){
//     // 在js中 为NAN 
//     record[s[i]-'a']++
// }
// for(let j=0;j<t.length;j++){
//     record[t[j]-'a']--
// }
// for(let k=0;k<26;k++){
//     if(record[k]!=0)
//     return false
// }
// return true

// };

var isAnagram = function(s, t) {
    const record = new Array(26).fill(0)
    const base = "a".charCodeAt()
    for(const i of s){
        record[i.charCodeAt()-base]++
    }
    for(const i of t){
        record[i.charCodeAt()-base]--
    }
    for(let i=0;i<26;i++)
    {
        if(record[i]!==0)
        return false
    }
    return true
}

‘b’-'a' NaN

const i of s  遍历字符串中的每一位

两个数组的交集

用集合来做

/**
 * @param {number[]} nums1
 * @param {number[]} nums2
 * @return {number[]}
 */
var intersection = function(nums1, nums2) {
// 用集合怎么做
const set1 = new Set(nums1)
const set2 = new Set(nums2)

// 不能用const 
let array = Array.from(set2)
let array1 = []
let k=0
for(let i=0; i<array.length;i++){
if(set1.has(array[i])){
array1[k++]=array[i]
}
}
return array1
};

思路

JS创建一个集合

const set = new Set(num) 

集合转换成数组 

Array.from(set)

使用扩展运算符

[...set]

快乐数

/**
 * @param {number} n
 * @return {boolean}
 */
var getSum = function(n){
let sum = 0
while(n){
    sum+=(n%10) * (n%10)
    n=Math.floor(n/10)
}
return sum
};
var isHappy = function(n){
    let set = new Set()
    // 如果循环中某个值循环出现或==1 则出循环
    while(n!==1&&!set.has(n)){
        set.add(n)
        n=getSum(n)
    }
    return n===1
}
// var isHappy = function(n) {
// 无限循环 在求和的过程中 sum 会重复出现 
// 快速判断一个元素是否出现 在集合里 哈希法
// 求每个位置上的数字的平方和
// let sum=0
// let set = new Set()
// while(1){
//     sum=getSum(n)
//     //  = 是赋值 == 才是判断是否相等
//     // if(sum==1)
//     // return true
//     // set.end() 不是函数 

// }
// };

思路

求每个数的各个位置上的平方和

无限循环 在求和的过程中 sum会重新出现

两数之和

用哈希法做 map 

map是一种key-value的存储结构

/**
 * @param {number[]} nums
 * @param {number} target
 * @return {number[]}
 */
var twoSum = function(nums, target) {
// 用map怎么做
// map 是一种key-value的结构
// 这里key 存储元素的值 value 存储下标
let hash = {}
for(let i=0;i<nums.length;i++){
    if(hash[target-nums[i]]!==undefined){
        return [i,hash[target-nums[i]]]
    }
    hash[nums[i]]=i//如果没找到匹配对 就把访问过的元素和下标加入到map中

}
return []
};

思路

key存元素的值 value 存储元素的下标

遍历数组 在map中寻找匹配对

如果没找到匹配对 就把访问过的元素和下标加入到map中

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值