我报名参加金石计划1期挑战——瓜分10万奖池,这是我的第9篇文章 点击查看文章详情 🚀🚀
前言
昨天礼拜天,休息了一天。今天就开始向哈希表专题迈进了~
😁😁😁
242. 有效的字母异位词 - 力扣(LeetCode)
难度:🔥🔥
创建map对象
var isAnagram = function(s, t) {
// 如果是字母异位词的话,那么长度肯定是相等的
if(s.length != t.length) return false;
let map = { };
// 先把s字符串中的都存到map中
for(let key of s){
map[key] = (map[key] || 0 ) + 1
}
// 在t中存在字符a多于在s中存在的字符a(本质上是在s中存在而在t中不存在)
for(let key of t){
if(map[key]){
map[key]--;
if(map[key] < 0)
return false;
}
// 在t字符串中存在而在s字符串中不存在
else {
return false;
}
};
return true
}
难点
对象的遍历 for..in for..of
在进行对象的遍历的时候,有时候总是会搞混或者分不清for..in 和 for..of的区别
最明显的区别
- for...in 遍历得到 key
- for...of 遍历得到 value
运行过程
const arr = [10, 20,30]
for(let val in arr){
console.log('for...in', val)
}
console.log('====我是分隔符====')
for(let val of arr){
console.log('for...of', val)
}
结果
用map存储值
在这里,很容易形成一个惯性思维
let map = { };
for(let key of s){
map[key] = map[key] + 1
}
以为和直接求sum
一样,定义之后直接一顿+
就好了
擦亮我们的眼睛,这里初始化是一个对象类型
!!!
而不是之前简单的
let count = 0;
或者
let sum = 0;
如果按我们的惯性思维写,map[key]
就给我们玩成了NAN
类型了。
类似于
console(1 + undefined) // NAN
区间判断
- 两个数组长度不相等,直接放回false;
- 两个数组长度相等
若里面的值不一样,返回
false
若里面的值一样,但相同值的数量不一样,还是返回
false
注意对范围的控制!!!
349. 两个数组的交集 - 力扣(LeetCode)
难度:🔥🔥
Set实现
var intersection = function(nums1, nums2) {
let num1 = new Set(nums1);
let num2 = new Set();
for(let key of nums2){
if(num1.has(key)){
num2.add(key);
}
}
return Array.from(num2);
};
难点
细节
-
set
的方法不要忘了.has()
判断是否有该元素.add()
添加该元素 -
set
是类数组结构,所以最后要Array.from
方法将其转换成真实的数组
202. 快乐数 - 力扣(LeetCode)
难度: 🔥 🔥
Set实现
var isHappy = function(n) {
const getSum = (n) =>{
let sum = 0;
while(n){
sum = sum + (n%10)*(n%10);
n = Math.floor(n/10);
}
return sum;
}
let res = new Set();
while(!res.has(n)){
res.add(n);
n = getSum(n);
}
// 用map对象也能实现
// let map = {};
// while(!map[n]){
// map[n] = 1;
// n = getSum(n)
// }
return n == 1
};
这里也可以创建map
对象实现
难点
对n求和
对于刚刷算法的我们来说,对数字上每个位置的平方进行求和,也没有那么简单
const getSum = (n) =>{
let sum = 0;
while(n){
// 在当前位置进行操作
sum = sum + (n%10)*(n%10);
// n取下一位
n = Math.floor(n/10);
}
return sum;
}
怎么理解无限循环?
让n=2
作为一个测试用例
并在while
循环里打log
可以很清楚的看到,当n
再一次等于4时,就进入了这个无限的循环了
// 只有n没有重复出现,才能进入循环
// 因此用Set去判断是否用重复
while(!res.has(n)){
{
1. 两数之和 - 力扣(LeetCode)
难度:🔥 🔥
暴力
var twoSum = function(nums, target) {
for(let i = 0, len = nums.length;i < len;i++){
// 因为同一元素不允许重复出现,所以从i的下一位开始遍历
for(let j = i + 1;j < len;j++) {
if(nums[i] + nums[j] === target) {
return [i, j];
}
}
}
// 所有样例都是有返回结果的,这里无所谓
return [-1, -1];
};
暴力解法是我们都能想到的,但是我们要有这样的一种本能:
当发现自己的代码里有两层循环时,先反思一下,能不能用空间换时间,把它优化成一层循环。
创建Map对象
这里我还是超级推荐修言老师的思路,后面我直接照搬了~
拿我们这道题来说,其实二层遍历是完全不必要的。
大家记住一个结论:几乎所有的求和问题,都可以转化为求差问题。 这道题就是一个典型的例子,通过把求和问题转化为求差问题,事情会变得更加简单。
我们可以在遍历数组的过程中,增加一个 Map
来记录已经遍历过的数字及其对应的索引值。然后每遍历到一个新数字的时候,都回到 Map
里去查询 targetNum
与该数的差值是否已经在前面的数字中出现过了。若出现过,那么答案已然显现,我们就不必再往下走了。
我们以 nums = [2, 7, 11, 15]
这个数组为例,来模拟一下这个思路:
第一次遍历到 2,此时 Map 为空:
以 2 为 key,索引 0 为 value 作存储,继续往下走;遇到了 7:
计算 targetNum 和 7 的差值为2,去 Map 中检索 2 这个 key,发现是之前出现过的值:
那么 2 和 7 的索引组合就是这道题的答案啦。
var twoSum = function(nums, target) {
let map = {};
for(let i = 0; i < nums.length ; i++){
let diff = target - nums[i];
if(map[diff] == undefined){
map[nums[i]] = i;
}
else{
return [map[diff],i]
}
}
};
难点
判断map是否重复
这里最最最容易错!!!
一般我们判断map
里的值是否重复时是这样写的:
if(map[diff]){
}
但这里我们不可以,因为map
的值是数组的索引,索引会取到0
!!!
所以我们要写成下面这种方式
if(map[diff] == undefined){
}
收获
今天哈希表题型不难,今天的收获都在一些js语法的细节上了。
- 有效的字母异位词:理清了一下
for...in
和for...of
的区别 - 两个数组的交集: 熟悉了
set
的api
- 快乐数:对数字
n
各个位置的求和 - 两数之和:在
map
判断值是否存在时,也是有特例的
今天就到这里了~
⭐⭐⭐