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

242.有效的字母异位词

题目链接:242.有效的字母异位词

文档讲解:代码随想录/有效的字母异位词

视频讲解:视频讲解-有效的字母异位词

状态:已完成(1遍)

解题过程 

看到题目的第一想法

 我的第一想法和哈希没有半点关系,俗称笨办法,单词转换成字母数组,排个序,然后再转换成单词,看看一不一样就行了。

/**
 * @param {string} s
 * @param {string} t
 * @return {boolean}
 */
var isAnagram = function (s, t) {
    if (s.length !== t.length) return false;
    let sortS = s.split('').sort().join('');
    let sortT = t.split('').sort().join('');
    if (sortS == sortT) {
        return true;
    } else {
        return false;
    }
};

运行、提交都成功,那么看看代码随想录的哈希解法。

看完代码随想录之后的想法 

这道题的文字讲解JS给了两版哈希解法,第一种是设一个长度为26的数组,来记录字符串各字母出现的次数,第二种是直接用Map键值对记录,个人还是比较习惯第二种。手搓一版问题不大。

/**
 * @param {string} s
 * @param {string} t
 * @return {boolean}
 */
var isAnagram = function (s, t) {
    if(s.length !== t.length) return false;
    let hashMap = {};
    for(let i of s){
        if(!hashMap[i]){
            hashMap[i] = 1;
        }else{
            hashMap[i] +=1;
        }
    }
    for(let i of t){
        if(!hashMap[i]){
            return false;
        }else{
            hashMap[i] -=1;
        }
    }
    return true;
};

总结

这道题的笨办法代码看上去还是挺简便的,GPT一下优劣。

两种方法的时间复杂度在最坏情况下都是线性的,但在实际应用中可能会有差异。

就代码的简洁性和可读性而言,第二段代码使用了一个哈希表来计数字符出现的次数,代码逻辑相对清晰,容易理解。第一段代码则通过排序的方式来比较字符串是否相同,代码较为简洁。

综合考虑,如果字符串长度较小且不会存在大量重复字符,第一段代码使用排序的方式可能更简洁有效。但如果字符串长度较大或存在大量重复字符,第二段代码使用哈希表的方式可能更高效,因为它可以在一次遍历过程中完成计数。


 349.两个数组的交集

题目链接:349.两个数组的交集

文档讲解:代码随想录/两个数组的交集

视频讲解:视频讲解-两个数组的交集

状态:已完成(1遍)

解题过程  

看到题目的第一想法

想了想,感觉和上一道题有点相似,我继续在第一个数组中遍历,出现的数字当作键值对记录在哈希表中,然后在第二个数组中遍历,看看有没有对应的键,有的话记在输出数组中;

/**
 * @param {number[]} nums1
 * @param {number[]} nums2
 * @return {number[]}
 */
var intersection = function(nums1, nums2) {
    let hashMap = {};
    let ans = [];
    for(let i of nums1){
        if(!hashMap[i]){//记录nums1中所有出现的数字,键:数字,值:1
            hashMap[i] =1;
        }
    }
    for(let j of nums2){
        if(hashMap[j]==1){//如果nums2中的数字出现在hashMap的键中
            ans.push(j);//答案推入一个此数字
            hashMap[j] = 0;//给对应的值改成0,不然会重复推入答案
        }
    }
    return ans;
};

 看完代码随想录之后的想法 

原来用Set可以自动实现去重,放进Set的就是唯一的。还学到了&&的短路特性。

讲解代码如下:

/**
 * @param {number[]} nums1
 * @param {number[]} nums2
 * @return {number[]}
 */
var intersection = function(nums1, nums2) {
    // 根据数组大小交换操作的数组
    if(nums1.length < nums2.length) {
        const _ = nums1;
        nums1 = nums2;
        nums2 = _;
    }
    const nums1Set = new Set(nums1);
    const resSet = new Set();
    // for(const n of nums2) {
    //     nums1Set.has(n) && resSet.add(n);
    // }
    // 循环 比 迭代器快
    for(let i = nums2.length - 1; i >= 0; i--) {
        nums1Set.has(nums2[i]) && resSet.add(nums2[i]);
    }
    return Array.from(resSet);
};

总结

使用数组来做哈希的题目,是因为题目都限制了数值的大小。

而且如果哈希值比较少、特别分散、跨度非常大,使用数组就造成空间的极大浪费

此时就要使用另一种结构体了,set


 202.快乐数

题目链接:202.快乐数

文档讲解:代码随想录/快乐数

视频讲解:无

状态:已完成(1遍)

解题过程  

看到题目的第一想法

如果这个数各个位数的数字平方和加起来不是1的话就一直加下去,如果是1就输出true,每次加完之后把这个数字记录进set里,要是set里已经有了,那说明肯定进入循环了,输出false。

/**
 * @param {number} n
 * @return {boolean}
 */
var isHappy = function(n) {
    let allCount = n;//每次各个位数加起来的和
    let set = new Set();
    while(allCount!==1){
        let allNums = allCount.toString().split('');
        allCount = allNums.reduce((a,b)=>{
            return a+b*b
            },0);
        if(set.has(allCount)) return false;
        set.add(allCount);
    }
    return true;
};

运行提交都没问题,那么看看文字讲解。 

 看完代码随想录之后的想法 

JS部分用了四种方法,综合来看感觉还是用reduce来求各个位数的数字平方和更简便一些,与解法四有些许差别,但我感觉直接将n赋值给allCount也没问题。

总结

这道题复习了哈希的Set用法。


1.两数之和

题目链接:1.两数之和

文档讲解:代码随想录/两数之和

视频讲解:视频讲解-两数之和

状态:已完成(1遍)

解题过程 

看到题目的第一想法

 双重for循环的想法按捺不住,先写一版看看。

/**
 * @param {number[]} nums
 * @param {number} target
 * @return {number[]}
 */
var twoSum = function(nums, target) {
    for(let i = 0;i<nums.length-1;i++){
        for(let j = i+1;j<nums.length;j++){
            if((nums[i]+nums[j])==target) return [i,j];
        }
    }
};

看着真顺眼哈哈,不过还得学习哈希方法。

每遍历到nums中的一个数,算出另一个目标加数是多少,然后看看这个目标数是否在哈希表中存在,如果存在,那么输出结果,如果不存在,就把当前遍历的数存进哈希表。

/**
 * @param {number[]} nums
 * @param {number} target
 * @return {number[]}
 */
var twoSum = function(nums, target) {
    let hashMap = {};
    let targetNum;
    for(let i = 0;i<nums.length;i++){
        targetNum = target - nums[i];
        if(!(hashMap[targetNum])){
            hashMap[nums[i]] = i;
        }else{
            return [i,hashMap[targetNum]]
        }
    }
};

这下真小丑了,写完感觉没问题,但是就是不成功,debug了一下,发现,如果后面某个数的要找的另一个数是数组的第0个数,那么我的!0能让他也变成true。。。老老实实改成下面这版吧。

/**
 * @param {number[]} nums
 * @param {number} target
 * @return {number[]}
 */
var twoSum = function(nums, target) {
    let hashMap = {};
    let targetNum;
    for(let i = 0;i<nums.length;i++){
        targetNum = target - nums[i];
        if(hashMap[targetNum]==undefined){
            hashMap[nums[i]] = i;
        }else{
            return [i,hashMap[targetNum]]
        }
    }
};

这下没问题了。 

看完代码随想录之后的想法 

这道题目的思路跟我想的大概一致,就是上面那个bug太小丑了,各位看到了就别犯这种错误了哈哈。

总结

在此卡卡西一段文字讲解中关于哈希三种方法的对比。

因为本题,我们不仅要知道元素有没有遍历过,还要知道这个元素对应的下标,需要使用 key value结构来存放,key来存元素,value来存下标,那么使用map正合适。

再来看一下使用数组和set来做哈希法的局限。

  • 数组的大小是受限制的,而且如果元素很少,而哈希值太大会造成内存空间的浪费。
  • set是一个集合,里面放的元素只能是一个key,而两数之和这道题目,不仅要判断y是否存在而且还要记录y的下标位置,因为要返回x 和 y的下标。所以set 也不能用。

此时就要选择另一种数据结构:map ,map是一种key value的存储结构,可以用key保存数值,用value再保存数值所在的下标。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值