✅✅代码随想录算法训练营Day6 | | 242.有效的字母异位词 ,349. 两个数组的交集 , 202. 快乐数 ,1. 两数之和

328 阅读4分钟

我报名参加金石计划1期挑战——瓜分10万奖池,这是我的第9篇文章 点击查看文章详情 🚀🚀

前言

昨天礼拜天,休息了一天。今天就开始向哈希表专题迈进了~

😁😁😁

242. 有效的字母异位词 - 力扣(LeetCode)

难度:🔥🔥

image.png

创建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)
}

结果 image.png

用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)

难度:🔥🔥

image.png

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)

难度: 🔥 🔥

image.png

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 image.png 可以很清楚的看到,当n再一次等于4时,就进入了这个无限的循环了

// 只有n没有重复出现,才能进入循环
// 因此用Set去判断是否用重复
while(!res.has(n)){

{

1. 两数之和 - 力扣(LeetCode)

难度:🔥 🔥

image.png

暴力

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 为空:

image.png

以 2 为 key,索引 0 为 value 作存储,继续往下走;遇到了 7:

image.png 计算 targetNum 和 7 的差值为2,去 Map 中检索 2 这个 key,发现是之前出现过的值:

image.png 那么 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...infor...of的区别
  • 两个数组的交集: 熟悉了setapi
  • 快乐数:对数字n各个位置的求和
  • 两数之和:在map判断值是否存在时,也是有特例的

今天就到这里了~

⭐⭐⭐

参考文档

for...in 和 for...of有什么区别 - 掘金 (juejin.cn)