力扣算法之哈希表

hash表

基本概念

哈希表是根据关键码的值而直接进行访问的数据结构,比如数组就是一张哈希表(表中关键码就是数组的索引下标,然后通过下标直接访问数组中的元素)。
力扣算法之哈希表_第1张图片

解决的问题

一般哈希表都是用来快速判断一个元素是否出现集合里

hash碰撞

力扣算法之哈希表_第2张图片
如图所示,小李和小王都映射到了索引下标 1 的位置,这一现象叫做哈希碰撞。

哈希碰撞的两种解决方法

  • 拉链法
    • 将发生冲突的元素存储在链表中, 这样就可以通过索引找到小李和小王了。
    • 拉链法就是要选择适当的哈希表的大小,这样既不会因为数组空值而浪费大量内存,也不会因为链表太长而在查找上浪费太多时间。
  • 线性探测法
    • 依靠哈希表中的空位来解决碰撞问题。
    • 例如冲突的位置,放了小李,那么就向下找一个空位放置小王的信息。
    • 要求tableSize一定要大于dataSize ,要不然哈希表上就没有空置的位置来存放冲突的数据了。

常见三种hash结构

  • 数组
  • set(集合)
  • map(映射)

总结

  • 当我们遇到了要快速判断一个元素是否出现集合里的时候,就要考虑哈希法。
  • 哈希法是牺牲了空间换取了时间,因为我们要使用额外的数组set或者是map存放数据,才能实现快速的查找。

示例

242.有效的字母异位词
力扣算法之哈希表_第3张图片
解答:

var isAnagram = function(s, t) {
    if(s.length !== t.length) return false;
    // 数组也是一种hash结构
    const arr = new Array(26).fill(0);
    const base = 'a'.charCodeAt();
    for (const x of s){
        arr[x.charCodeAt() - base]++;
    }
    for (const x of t){
        if(!arr[x.charCodeAt() - base]) return false;
        arr[x.charCodeAt() - base]--;
    }
    return true;
};

349. 两个数组的交集
力扣算法之哈希表_第4张图片
解答:

var intersection = function(nums1, nums2) {
    // 根据数组大小进行交换数组,将大一点的数组作为基准,一直将nums1作为大一点的数组
    if (nums1.length < nums2.length) {
        [nums1, nums2] = [nums2, nums1];
    }
    let set1 = new Set(nums1);
    let set2 = new Set();
    for (const x of nums2){
        set1.has(x) && set2.add(x);
    }
    return Array.from(set2);
};

第202题. 快乐数
力扣算法之哈希表_第5张图片
解答:

var isHappy = function(n) {
    let m = new Map();
    // 求n各个位上的数的平方和
    const getSum = (n) => {
        let sum = 0;
        while (n){
            sum += ((n % 10) * (n % 10));
            n = Math.floor(n / 10);
        }
        return sum;
    }
    while (true){
    	// 如果出现了之前已经出现过的数,说明出现了死循环,就是false
        if(m.has(n)) return false;
        if(n === 1) return true;
        m.set(n, 1);
        n = getSum(n);
    }
};

1. 两数之和
力扣算法之哈希表_第6张图片
解答:

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

第454题.四数相加II
力扣算法之哈希表_第7张图片
解答:

var fourSumCount = function(nums1, nums2, nums3, nums4) {
    let count = 0;
    let twoMap = new Map();
    for (let x of nums1) {
        for (let y of nums2) {
            // 可能不存在,所以隐式做一个判断
            twoMap.set(x + y, (twoMap.get(x + y) || 0) + 1);
        }
    }
    for (let x of nums3) {
        for (let y of nums4) {
            // 可能不存在,所以隐式做一个判断
            count += (twoMap.get(-(x + y)) || 0);
        }
    }
    return count;
};

383. 赎金信
力扣算法之哈希表_第8张图片
解答:

var canConstruct = function(ransomNote, magazine) {
    let arr = new Array(26).fill(0);
    const base = 'a'.charCodeAt();
    for (const x of magazine){
        arr[x.charCodeAt() - base]++;
    }
    for (const x of ransomNote){
        if(!arr[x.charCodeAt() - base]) return false;
        arr[x.charCodeAt() - base]--;
    }
    return true;
};

第15题. 三数之和
力扣算法之哈希表_第9张图片
解答:

var threeSum = function(nums) {
    if(nums.length < 3) return [];
    let res = [];
    nums.sort((a, b) => a - b);
    for(let i = 0; i < nums.length - 2; i++){
        if(nums[i] > 0) break;
        // a 去重
        if (i > 0 && nums[i] === nums[i - 1]) continue;
        let left = i + 1, right = nums.length - 1;
        while (left < right){
            let sum = nums[i] + nums[left] + nums[right];
            if(sum > 0){
                right--;
                continue;
            } else if(sum < 0){
                left++;
                continue;
            } else {
                res.push([nums[i], nums[left], nums[right]]);
            }
            // b c 去重
            while (left < right && nums[left] === nums[++left]);
            while (left < right && nums[right] === nums[--right]);
        }
    }
    return res;
};

第18题. 四数之和
力扣算法之哈希表_第10张图片
解答:

var fourSum = function(nums, target) {
    const len = nums.length;
    if(len < 4) return [];
    nums.sort((a, b) => a - b);
    const res = [];
    for(let i = 0; i < len - 3; i++) {
        // 去重i
        if(i > 0 && nums[i] === nums[i - 1]) continue;
        for(let j = i + 1; j < len - 2; j++) {
            // 去重j
            if(j > i + 1 && nums[j] === nums[j - 1]) continue;
            let l = j + 1, r = len - 1;
            while(l < r) {
                const sum = nums[i] + nums[j] + nums[l] + nums[r];
                if(sum < target) { l++; continue}
                if(sum > target) { r--; continue}
                res.push([nums[i], nums[j], nums[l], nums[r]]);
                while(l < r && nums[l] === nums[++l]);
                while(l < r && nums[r] === nums[--r]);
            }
        } 
    }
    return res;
};

你可能感兴趣的:(算法,javascript)