代码随想录算法训练营Day6|哈希表理论基础、242.有效的字母异位词、349.两个数组的交集、202.快乐数、1.两数之和

一、哈希表理论基础

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

一般哈希表都是用来快速判断一个元素是否出现集合里。如果使用枚举法的话,时间复杂度为O(n),而使用哈希表的话则只需要O(1)。

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

哈希碰撞:如果需要取哈希数的值的总数量大于哈希表的长度,就会导致几个数据被映射到哈希表同一个索引下标的位置。那么可以使用两种办法,一种是拉链法,即出现碰撞的部位使用链表按序排放;一种是线性探测法,这种方法要求哈希表全长较大,就是向下寻找空位放入数据。

js当中一般使用map而不使用set。

使用哈希表是一种牺牲空间换时间的做法。

二、242 有效的字母异位词

  1. 题目链接:https://leetcode.cn/problems/valid-anagram/

  1. 思路:为两个字符串分别构造长度为26的数组,用每个字符的ascii码顺序来当作键,每次加一,最后比较两个数组。时间复杂度为O(n)

  1. 代码:

var isAnagram = function(s, t) {
    // 记住fill这个方法
    var sMap = new Array(26).fill(0);
    var tMap = new Array(26).fill(0);
    var a = 'a';
    for (let i=0; i<s.length; i++) {
        var index = s.charCodeAt(i) - a.charCodeAt(0);
        sMap[index] = sMap[index] ? sMap[index] + 1 : 1;
    }
    for (let i=0; i<t.length; i++) {
        var index = t.charCodeAt(i) - a.charCodeAt(0);
        tMap[index] = tMap[index] ? tMap[index] + 1 : 1;
    }
    // 两个数组不能直接用==来比较
    return sMap.toString() == tMap.toString();
};

  1. 383 赎金信

题目链接:https://leetcode.cn/problems/ransom-note/

思路:和上题几乎一样,可以用26位数组也可以用map。这里展示的代码用的是map。

代码:

var canConstruct = function(ransomNote, magazine) {
    var array = magazine.split('');
    var map = new Map();
    for (let i=0; i<array.length; i++) {
        map.set(array[i], map.has(array[i]) ? map.get(array[i]) + 1 : 1);
    }
    var note = ransomNote.split('');
    for (let i=0; i<note.length; i++) {
        if (!map.has(note[i])) {
            return false;
        }
        else {
            if (map.get(note[i]) == 1) {
                map.delete(note[i]);
            }
            else {
                map.set(note[i], map.get(note[i]) - 1);
            }
        }
    }
    return true;
};

  1. 49 字母异位词分组

题目链接:https://leetcode.cn/problems/group-anagrams/

思路:将每个词产生的26位数组作为object的key,而将这个词本身添加进value的列表当中。最后返回这个object的所有value。为什么不用map?因为map的键不可以是数组。哈希表的实现是基于地址的,两个所有元素相等但地址不同的数组是不一样的,不会在一个map的键下面。

代码:

var groupAnagrams = function(strs) {
    const map = new Object();
    for (let s of strs) {
        const count = new Array(26).fill(0);
        for (let c of s) {
            count[c.charCodeAt() - 'a'.charCodeAt()]++;
        }
        map[count] ? map[count].push(s) : map[count] = [s];
    }
    return Object.values(map);
};

也可以用排序后的字符串当作键。

  1. 438 找到字符串中所有字母异位词

题目链接:https://leetcode.cn/problems/find-all-anagrams-in-a-string/

思路:将初始的字典找出,然后利用滑动窗口解题。

三、349 两个数组的交集

  1. 题目链接:https://leetcode.cn/problems/intersection-of-two-arrays/

  1. 思路:创建一个数组的map,再用另一个数组与之比较

  1. 代码:

var intersection = function(nums1, nums2) {
    var result = [];
    var map = new Map();
    for (let i=0; i<nums1.length; i++) {
        map.set(nums1[i], map.has(nums1[i]) ? map.get(nums1[i]) + 1 : 1);
    }
    for (let i=0; i<nums2.length; i++) {
        if (map.has(nums2[i])) {
            // 每次找到之后在map中删掉,以免下次再找到重复
            map.delete(nums2[i]);
            result.push(nums2[i]);
        }
    }
    return result;
};

  1. 350 两个数组的交集II

题目链接:https://leetcode.cn/problems/intersection-of-two-arrays-ii/

思路:与349其实很像,但是这一次不能找到了就将map中对应的值删掉,而是每次减一,直到不能减了再删掉,这样才能让共同出现的次数与其实际情况相同。

代码:

var intersect = function(nums1, nums2) {
    var result = [];
    var map = new Map();
    for (let i=0; i<nums1.length; i++) {
        map.set(nums1[i], map.has(nums1[i]) ? map.get(nums1[i]) + 1 : 1);
    }
    for (let i=0; i<nums2.length; i++) {
        if (map.has(nums2[i])) {
            result.push(nums2[i]);
            if (map.get(nums2[i]) == 1) {
                map.delete(nums2[i]);
            }
            else {
                map.set(nums2[i], map.get(nums2[i]) - 1);
            }
        }
    }
    return result;
};

四、202 快乐数

  1. 题目链接:https://leetcode.cn/problems/happy-number/

  1. 思路:用一个history数组记录下目前所有得出的数据,只要曾经出现重复就返回false,出现1就返回true

  1. 代码:

var isHappy = function(n) {
    var history = [];
    var number = n;
    while (true) {
        var array = number.toString().split('');
        var result = 0;
        for (let i=0; i<array.length; i++) {
            result += array[i] * array[i];
        }
        if (result == 1) {
            return true;
        }
        if (history.indexOf(result) !== -1) {
            return false;
        }
        else {
            history.push(result);
            number = result;
        }
    }
};

五、1 两数之和

  1. 题目链接:https://leetcode.cn/problems/two-sum/

  1. 思路:依次遍历数组,既然只有一组符合答案的数据,那么可以每次经过的时候都判断是否有target-当前值的这样一个数据存在在map中,如果有的话就返回,没有的话在map中加入[value: key]键值对。

  1. 代码:

var twoSum = function(nums, target) {
    var map = new Map();
    for (let i=0; i<nums.length; i++) {
        if (map.has(target - nums[i])) {
            return [map.get(target - nums[i]), i];
        }
        else {
            map.set(nums[i], i);
        }
    }
};

今日学习时长:2h左右

总结:今天438题脑袋转不动先不写了,总体还可以,对map的掌握熟练了一些,下次刷的时候需重点注意438和49。今天学到了map的键不可以是数组,因此有时需要合理使用toString()函数,而且记住fill函数, var array = new Array(26).fill(0)。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值