代码随想录刷题笔记Day6–哈希表简介及有效的字母异位词、两个数组的交集、快乐数 、两数之和

代码随想录刷题笔记Day6–哈希表简介及有效的字母异位词、两个数组的交集快乐数两数之和

一、哈希表基础知识简介

​ 哈希表(英文名字为Hash table,国内也有一些算法书籍翻译为散列表,大家看到这两个名称知道都是指hash table就可以了)。

​ 哈希表是根据关键码的值而直接进行访问的数据结构。

哈希表1

解决的问题:快速判断一个元素是否出现在集合里面

常见的三种哈希结构

  • 数组

  • set(集合)

  • map(映射)

JS中的set和map数据类型

​ 在ES6之前,我们存储数据的结构主要是两种:数组和对象

​ 在ES6之后,新增了另外两种数据结构:Set、Map,以及它们的另外两种形式WeakSet、WeakMap

一、Set
1、基本用法
  ES6提供了新的数据结构Set。 它类似于数组,但是**成员的值都是唯一的,没有重复的值**。Set本身是一个构造函数, 用来生成Set数	据结构。
//利用add方法向set结构添加成员,结果表明set结构是不会添加重复的值。
var s=new Set();
[2,3,4,5,3,2,4,3].map(x=>s.add(x))
for(i of s) console.log(i);//2,3,4,5
//Set可以接受一个数组作为参数,用于初始化
var set=new Set([1,2,3,4,4,5]);
[...set]//[1,2,3,4,5]
//向Set加入值时,不会发生类型转换,5和'5'是不同的两个值
2、四种操作方法
  • add(value):添加某个值,返回Set结构本身。
  • delete(value):删除某个值,返回一个布尔值,表示删除是否成功。
  • has(value):返回一个布尔值,表示参数是否为Set的成员。
  • clear():清除所有成员,没有返回值。
3、4种遍历方法

​ Set结构的实例有4个遍历方法,可用于遍历成员。

  • keys():返回一个键名的遍历器。
  • values():返回一个键值的遍历器。
  • entries():返回一个键值对的遍历器。
  • forEach(): 使用回调函数遍历每个成员。

【注:】由于Set结构没有键名,只有键值(或者说键名和键值是同一个值),所以keys方法和values方法的行为完全一致。

4、Set的应用

1)Set转化为数组

由于扩展运算符( … )内部使用for…of循环,所以也可以用于Set结构。代码如下。

let set = new Set(['red', 'green', 'blue']);
let arr = [...set];
// ['red', 'green', 'blue']

2)去除数组的重复元素

方法一: 如下代码。

let arr=[3,5,2,2,5,5];
let unique = [...new Set(arr)];
//[3,5,2];

3)实现并集(Union)、交集(Intersect)、差集(Difference)

let a=new Set([1,2,3]);
let b=new Set([4,3,2]);
//并集
let union=new Set([...a,...b]);
//[1,2,3,4]
//交集
let intersect=new Set([...a].filter(x=>b.has(x)));
//[2,3]
//差集
let difference=new Set([...a].filter(x=>!b.has(x)));
//[1]
二、Map
1、基本用法

JavaScript的对象(Object)本质上是键值对的集合(Hash结构),但是只能用字符串作为键

var data = {};
var element = document.getElementById("myDiv");

data[element] = metadata;
data["[object HTMLDivElement]"] // metadata

为了解决这个问题,ES6 提供了Map数据结构。它类似于对象,也是键值对的集合,但是“键”的范围不限于字符串,各种类型的值( 包括对象)都可以当作键。也就是说,Object 结构提供了“字符串一值”的对应,Map结构提供了“值一值"的对应,是-种更完善的Hash结构实现。
如果你需要“键值对”的数据结构,Map比Object更合适。

var m= new Map();
var o ={p: "Hello World"};

m.set(o, "content")
m.get(o) // "content"

m.has(o) // true
m.delete(o) // true
m.has(o) // false

2、五种操作方法
  • size属性
  • set(key, value)
  • get(key)
  • has(key)
  • delete(key)
  • clear()
//size属性
let map = new Map();
map.set('foo', true);
map.set('bar', false);
map.size //2

//set(key,value)
var m = new Map();
m.set("edition", 6) //键是字符串
m.set(262"standard") //键是数值
m.set(undefined, "nah") //键是undefined

//get(key)
var m = new Map();
var hello = function() {console.log("hello");}
m.set(hello, "Hello ES6!") //键是函数
m.get(hello) // Hello ES6!

//has(key)
var m = new Map();
m.set("edition", 6);
m.set(262, "standard");
m.set(undefined, "nah' );
m.has("edition")// true
m.has("years")// false
m.has(262)// true
m.has(undefined)// true

//delete(key)
var m = new Map();
m.set(undefined, "nah");
m.has(undefined)// true
m.delete(undefined)
m.has(undefined)// false

//clear()
let map = new Map();
map.set('foo', true);
map.set('bar', false);
map.size // 2
map.clear()
map.size // 0

3、四种遍历方法

Map原生提供3个遍历器生成函数和1个遍历方法。

  • keys():返回键名的遍历器。
  • values():返回键值的遍历器。
  • entries():返回所有成员的遍历器。
  • forEach():遍历Map的所有成员。

二、leetcode题目

LeetCode 242. 有效的字母异位词

题目描述:

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

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

示例 1:

输入: s = "anagram", t = "nagaram"
输出: true

示例 2:

输入: s = "rat", t = "car"
输出: false

解题思路

  • 本题数据量不多,可以使用数据来解决问题
  • 在统计数组s的每一个字符出现的次数时,在计数数组这个字符对应的索引值处,对该数++,统计数组t的每一个字符出现的次数时,对计数数组这个字符对应的索引值处,对该数–

解法:

/**
 * @param {string} s
 * @param {string} t
 * @return {boolean}
 */
var isAnagram = function(s, t) {
	let arr=Array.from(Array(26).fill(0));
	for(i of s)
	{
	   let temp=s[i].charCodeAt()-'a'.charCodeAt();
	   ++arr[temp];
	}
	for(i of t)
	{
	   let temp=t[i].charCodeAt()-'a'.charCodeAt();
	   --arr[temp];
	}
	 for(let i=0;i<arr.length;i++)
   {
       if(arr[i]!=0)
       return false;
   }
   return true
};

反思:

  • 生成26项为0的数组的代码老是忘记 let arr=Array.from(Array(26).fill(0));
  • 每个字符对应的ascii码的代码 charCodeAt()
  • 统计s++,统计t–这种思路未考虑到,自己写的时候选择复杂的map,想前面是字符串为键,后面值则为统计数,比较麻烦。

LeetCode 349. 两个数组的交集

题目描述:给定两个数组,编写一个函数来计算它们的交集。

示例 1:

输入:nums1 = [1,2,2,1], nums2 = [2,2]
输出:[2]

示例 2:

输入:nums1 = [4,9,5], nums2 = [9,4,9,8,4]
输出:[9,4]
解释:[4,9] 也是可通过的

解题思路

  • 本题的解题思路,使用set,因为在set中,值不能重复,故过滤到在一个数组中重复的值
  • 利用[…set1]将set转换为数组,即可使用数组的filter方法,遍历set1中的值,set2也有的值

解法:

/**
 * @param {number[]} nums1
 * @param {number[]} nums2
 * @return {number[]}
 */
var intersection = function(nums1, nums2) {
    let set1=new Set(nums1);
    let set2=new Set(nums2);
    let intersect=new Set([...set1].filter(x=>set2.has(x)));
     return intersect = [...intersect]
};

反思:

1、数组和set的转化

数组---->set let set1=new Set(nums1); set----->数组 […set1]

2、数组有filter方法


LeetCode 202. 快乐数

题目描述:编写一个算法来判断一个数 n 是不是快乐数。

「快乐数」 定义为:

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

如果 n快乐数 就返回 true ;不是,则返回 false

示例 1:

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

示例 2:

输入:n = 2
输出:false

解题思路

  • 一开始看到无限循环比较懵,没想到如何使用set解决,后看了卡哥解析,**求和的过程中,sum会重复出现,这对解题很重要!**才明白如何解决此题。

​ 本题,来判断这个sum是否重复出现,如果重复了就是return false, 否则一直找到sum为1为止。

  • 取出数值各个位上的数字

解法:

本人解法(在处理数值各个位上数字时,仍然过于繁琐)

/**
 * @param {number} n
 * @return {boolean}
 */
var getsumn=function(n){
    let arr=[],sum=0;let temp=n;
    while(temp)
    {  
        temp=Math.floor(temp/10);
        arr.push(n-temp*10);
        n=temp;
    }
    for(i of arr)
    {
        sum=i*i+sum;
    }
    
    return sum;
}

var isHappy = function(n) {
     let set_1=new Set();
  
     while(true)
     {   n=getsumn(n);
        if(set_1.has(n))
        return false;
        if (n === 1) return true
        set_1.add(n);
     }
};

卡哥写法

var isHappy = function (n) {
    let m = new Map()

    const getSum = (num) => {
        let sum = 0
        while (n) {
            sum += (n % 10) ** 2
            n = Math.floor(n / 10)
        }
        return sum
    }

    while (true) {
        // n出现过,证明已陷入无限循环
        if (m.has(n)) return false
        if (n === 1) return true
        m.set(n, 1)
        n = getSum(n)
    }
}

LeetCode 1. 两数之和

题目描述:给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那 两个 整数,并返回它们的数组下标。

你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。

你可以按任意顺序返回答案。

示例 1:

输入:nums = [2,7,11,15], target = 9
输出:[0,1]
解释:因为 nums[0] + nums[1] == 9 ,返回 [0, 1] 。

示例 2:

输入:nums = [3,2,4], target = 6
输出:[1,2]

示例 3:

输入:nums = [3,3], target = 6
输出:[0,1]

解题思路:

遍历数组,看map(存放已经遍历过的数据)中是否存在target-当前值的数

解法:

本人解法

/**
 * @param {number[]} nums
 * @param {number} target
 * @return {number[]}
 */
var twoSum = function(nums, target) {
    let m=new Map();
    for(let i=0;i<nums.length;i++)
    {   
        let right=target-nums[i];
        if(m.has(right))
        return [i,m.get(right)];
        m.set(nums[i],i)
    }

};


反思:

  • 注意!!m.has(target) target是键而不是值

前面哈希表简介中的js的map和set数据结构有参考CSDN博主「征途黯然.」的原创文章,原文链接:https://blog.csdn.net/qq_43592352/article/details/103993479

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值