JavaScript:哈希表

news2024/11/15 11:13:34

文章目录

  • 哈希表
    • 242. 有效的字母异位词
      • 思路
      • 补充:JavaScript String charCodeAt() 方法
      • 代码详细分析
    • 349. 两个数组的交集
      • 代码分析
      • 补充:JavaScript Set 对象
      • 思考一下哈希是什么?什么时候使用?
      • 补充:js 数组 map() 基本用法
      • new Map()详细介绍
    • 1. 两数之和
      • 思路
      • 代码
    • 第454题.四数相加II
      • 思路
      • 代码以及分析
    • 总结
      • 什么是哈希表?
      • 什么时候使用哈希表?
      • 使用哈希法中的数据结构
      • js里面Set的使用方法
      • js里面Map的使用方法

哈希表

242. 有效的字母异位词

思路

为了方便举例,判断一下字符串s= “aee”, t = “eae”。
在这里插入图片描述

字符a到字符z的ASCII是26个连续的数值,所以字符a映射为下标0,相应的字符z映射为下标25。

再遍历 字符串s的时候,只需要将 s[i] - ‘a’ 所在的元素做+1 操作即可,并不需要记住字符a的ASCII,只要求出一个相对数值就可以了。 这样就将字符串s中字符出现的次数,统计出来了。

那看一下如何检查字符串t中是否出现了这些字符,同样在遍历字符串t的时候,对t中出现的字符映射哈希表索引上的数值再做-1的操作。

record数组如果有的元素不为零0,说明字符串s和t一定是谁多了字符或者谁少了字符,return false。

补充:JavaScript String charCodeAt() 方法

[图片]

代码详细分析

判断 s 的元素是否 t 都有
使用哈希:将 s 的每个元素存到索引里面,对应的值就是当前元素的个数
遍历 t 的元素,如果 s 里面有,个数减一,减到 < 0 时返回 false
如果 s 里面没有,返回false
如果 s 的元素刚好都减到 0 遍历 t结束 返回true
这三种情况其实可以合并,也就是遍历t还没遍历完时s里面已经没有了

具体见代码分析

/*
 * @lc app=leetcode.cn id=242 lang=javascript
 *
 * [242] 有效的字母异位词
 */

// @lc code=start
/**
 * @param {string} s
 * @param {string} t
 * @return {boolean}
 */
var isAnagram = function(s, t) {
    /* 
        使用哈希:把字符串每个字符作为键名,对应个数作为键值
        判断 t 有的字符 是否 s都包括
        思路:记录 s 每个字符个数,遍历 t, s存在一次,就减少一个数
    */
    if (s.length !== t.length) return false
    // 创建一个初始值都为 0 的数组
    // 因为要给每个数组键名对应的键值计数,所以需要把每个值初始值设为 0
    const resSet = new Array(26).fill(0)
    // 把每个字符传承对应的ASCII
    const base = "a".charCodeAt()
    // 遍历字符串
    for(const i of s) {
        // 记录每个字符的个数
        resSet[i.charCodeAt() - base] ++
    }
    for(const i of t) {
        // 如果当前键名不存在
        if(!resSet[i.charCodeAt() - base]) return false
        // 存在,便将个数减 1
        resSet[i.charCodeAt() - base]--
    }
    return true

};
// @lc code=end

349. 两个数组的交集

代码分析


/**
 * @param {number[]} nums1
 * @param {number[]} nums2
 * @return {number[]}
 */
var intersection = function(nums1, nums2) {
    // 这里我们让nums1为较长数组
    if(nums1.length < nums2.length) {
        const _ = nums1
        nums1 = nums2
        nums2 = _
    }
    // nums1去重
    const nums1Set = new Set(nums1)
    // 存储交集的元素
    const resSet = new Set()
    // 遍历nums2,nums1里面存在,就把当前元素添加到resSet里面
    for (const n of nums2) nums1Set.has(n) && resSet.add(n)
    // 返回数组的交集
    return Array.from(resSet)
};

补充:JavaScript Set 对象

此处不是完整的用法,只是上面代码涉及到了的,具体使用见总结

数组去重
创建新的 Set 对象

[图片]

思考一下哈希是什么?什么时候使用?

第202题. 快乐数
思路

  1. 求和 sum重复出现
  2. 遇到快速判断一个元素是否出现集合里的时候,考虑哈希算法
  3. sum重复出现,return false 否则一直找到sum = 1 为止
    代码

下面方法推荐使用方法一Map()和方法三Set()

// 方法一:使用Map方法
var isHappy = function (n) {
    let m = new Map()

    const getSum = (num) => {
        let sum = 0
        while (n) {
            sum += (n % 10) ** 2
            n = Math.floor(n / 10)
        }
        return sum
    }

    while (true) {
        // n出现过,证明已陷入无限循环
        if (m.has(n)) return false
        if (n === 1) return true
        m.set(n, 1)
        n = getSum(n)
    }
}

// 方法二:使用环形链表的思想 说明出现闭环 退出循环
var isHappy = function(n) {
    if (getN(n) == 1) return true;
    let a = getN(n), b = getN(getN(n));
    // 如果 a === b 
    while (b !== 1 && getN(b) !== 1 && a !== b) {
        a = getN(a);
        b = getN(getN(b));
    }
    return b === 1 || getN(b) === 1 ;
};

// 方法三:使用Set()更简洁
/**
 * @param {number} n
 * @return {boolean}
 */

var getSum = function (n) {
    let sum = 0;
    while (n) {
        sum += (n % 10) ** 2;
        n =  Math.floor(n/10);
    }
    return sum;
}
var isHappy = function(n) {
    let set = new Set();   // Set() 里的数是惟一的
    // 如果在循环中某个值重复出现,说明此时陷入死循环,也就说明这个值不是快乐数
    while (n !== 1 && !set.has(n)) {
        set.add(n);
        n = getSum(n);
    }
    return n === 1;
};

// 方法四:使用Set(),求和用reduce
var isHappy = function(n) {
    let set = new Set();
    let totalCount;
    while(totalCount !== 1) {
        let arr = (''+(totalCount || n)).split('');
        totalCount = arr.reduce((total, num) => {
            return total + num * num
        }, 0)
        if (set.has(totalCount)) {
            return false;
        }
        set.add(totalCount);
    }
    return true;
};

补充:js 数组 map() 基本用法

map() 方法返回一个新数组,数组中的元素为原始数组元素调用函数处理后的值。

var data = [3, 4, 5, 6];

var Squares = data.map(function (item) {
  return item * item;
});
console.log(Squares);
// [9, 16, 25, 36]

new Map()详细介绍

map.set(key,value)
map.size
map.get(key)
map.has(key)
map.delete(key)
map.clear()

(1)get() 方法用来获取一个 Map 对象中指定的元素。
(2)set() 方法为Map对象添加一个指定键(key)和值(value)的新元素。map的set属性就是添加东西的
(3)has() 返回一个bool值,用来表明map 中是否存在指定元素。

1. 两数之和

思路

  1. 创建一个空的Map
  2. 遍历数组,从第一个,满足当前Array.value + Map(key, value) = 9 则找到了
  3. 要是不满足,≠9,就把当前值添加到Map,接着遍历,直到找到满足条件的为止

代码

/**
 * @param {number[]} nums
 * @param {number} target
 * @return {number[]}
 */
var twoSum = function(nums, target) {
    let m = new Map()
    for (let i = 0; i < nums.length; i++) {
        // Map 里面的值 = target - nums[i] 不为空时,这时找到了匹配值
        if(m[target - nums[i]] !== undefined) {
            // 返回当前nums下标  和 m的下标
            return [i, m[target - nums[i]]]
        }
        // 如果没有匹配到,就把当前访问的元素和下表加到Map中
        m[nums[i]] = i
    }
    return m
};

第454题.四数相加II

思路

本题是使用哈希法的经典题目
这道题目是四个独立的数组,只要找到A[i] + B[j] + C[k] + D[l] = 0就可以,不用考虑有重复的四个元素相加等于0的情况

本题解题步骤:

  1. 首先定义 Map,key放a和b两数之和,value 放a和b两数之和出现的次数。
  2. 遍历大A和大B数组,统计两个数组元素之和,和出现的次数,放到map中。
  3. 定义int变量count,用来统计 a+b+c+d = 0 出现的次数。
  4. 在遍历大C和大D数组,找到如果 0-(c+d) 在map中出现过的话,就用count把map中key对应的value也就是出现次数统计出来。
  5. 最后返回统计值 count 就可以了

代码以及分析

/**
 * @param {number[]} nums1
 * @param {number[]} nums2
 * @param {number[]} nums3
 * @param {number[]} nums4
 * @return {number}
 */
var fourSumCount = function(nums1, nums2, nums3, nums4) {
    // 1 new Map
    const twoSumMap = new Map()
    let count = 0
    // 2 统计nums1 + nums2数组元素之和key 和出现的次数value 放到Map
    // 遍历 nums1,nums2 然后判断Map里面是否有这个元素,有次数+1,没有就增加这个元素
    for(const n1 of nums1) {
        for(const n2 of nums2) {
            const sum = n1 + n2
            if (twoSumMap.get(sum)) {
                twoSumMap.set(sum, twoSumMap.get(sum) + 1)
            } else {
                twoSumMap.set(sum, 1)
            }
        }
    }
    // 3 统计 nums3 + nums4 数组和, 0 - c - d 在Map出现过次数统计出来
    for(const n3 of nums3) {
        for(const n4 of nums4)  {
            const sum = n3 + n4
            if(twoSumMap.get(0-sum)) {
                count += twoSumMap.get(0-sum)
            }
        }
    }
    return count

};

总结

什么是哈希表?

哈希表中关键码就是数组的索引下标,然后通过下标直接访问数组中的元素

什么时候使用哈希表?

哈希表能解决什么问题呢,一般哈希表都是用来快速判断一个元素是否出现集合里。
哈希法也是牺牲了空间换取了时间,因为我们要使用额外的数组,set或者是map来存放数据,才能实现快速的查找。

例如要查询一个名字是否在这所学校里。
要枚举的话时间复杂度是O(n),但如果使用哈希表的话, 只需要O(1)就可以做到。
我们只需要初始化把这所学校里学生的名字都存在哈希表里,在查询的时候通过索引直接就可以知道这位同学在不在这所学校里了。
学生姓名映射到哈希表上就涉及到了hash function ,也就是哈希函数。
把学生的姓名直接映射为哈希表上的索引,然后就可以通过查询索引下标快速知道这位同学是否在这所学校里了。
stu[小明] = 0

使用哈希法中的数据结构

想使用哈希法来解决问题的时候,我们一般会选择如下三种数据结构。

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

js里面Set的使用方法

Set 是 ES6 中新增的一种数据类型,**用于存储一组不重复、无序的数据。**下面是 Set 的使用方法:

1.创建 Set

可以通过以下两种方式创建 Set:

使用 new 关键字创建:

let mySet = new Set();

使用数组来初始化 Set:

let mySet = new Set([1, 2, 3]);

2.添加元素

可以使用add()方法向 Set 中添加元素,如果元素已经存在,Set 不会进行任何操作。

mySet.add(4);

3.删除元素

可以使用delete()方法删除 Set 中的元素。

mySet.delete(4);

4.判断元素是否存在

可以使用 has() 方法判断 Set 中是否存在某个元素。

mySet.has(3); // true
mySet.has(4); // false

5.获取 Set 中元素的个数

可以使用size 属性获取 Set 中元素的个数。

mySet.size;

6.遍历 Set

可以使用 for...of 循环或者 forEach() 方法来遍历 Set。

for (let item of mySet) {
  console.log(item);
}
mySet.forEach(function(item) {
  console.log(item);
});

除此之外,Set 还有一些其他的方法,例如 clear()keys()values() 等,具体使用方法可以参考 MDN 文档

js里面Map的使用方法

Map 是 ES6 中新增的一种数据类型,用于存储键值对。下面是 Map 的使用方法:

1.创建 Map

可以通过以下两种方式创建 Map:

使用 new 关键字创建:

let myMap = new Map();

使用数组来初始化 Map:

let myMap = new Map([
  ["key1", "value1"],
  ["key2", "value2"]
]);

2.添加键值对

可以使用 set() 方法向 Map 中添加键值对,如果键已经存在,Map 会使用新值覆盖旧值。

myMap.set("key3", "value3");

3.删除键值对

可以使用 delete() 方法删除 Map 中的键值对。

myMap.delete(“key3”);
4.判断键是否存在

可以使用 has() 方法判断 Map 中是否存在某个键。

myMap.has("key2"); // true
myMap.has("key3"); // false

5.获取 Map 中键值对的个数

可以使用 size 属性获取 Map 中键值对的个数。

myMap.size;

6.遍历 Map

可以使用 for...of 循环或者 forEach() 方法来遍历 Map。

for (let [key, value] of myMap) {
  console.log(key + " = " + value);
}
myMap.forEach(function(value, key) {
  console.log(key + " = " + value);
});

除此之外,Map 还有一些其他的方法,例如 clear()、keys()、values() 等,具体使用方法可以参考 MDN 文档。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/488749.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

github使用workflow工作流git push后自动打包部署github pages

workflows介绍 根目录新建.github/workflows/docs.yml .github/workflows/ 目录是用于存放 GitHub Actions 工作流程文件的目录&#xff0c;该目录的文件名必须以 .yml 或 .yaml 为后缀名&#xff0c;否则 GitHub 将无法识别该文件为工作流程文件。这些工作流程文件可用于自动…

速锐得基于能源油气生产智能监控的物联网应用

自2016年速锐得基于商用车国六环保排放监控管理开发以来&#xff0c;我们同时也接触了很多涉及商用车领域的深入项目&#xff0c;包括了大庆油田、山东能源、兖矿集团、陕北矿业等多家能源巨头在数字化、科技、无线远程控制、监控管理、生产效能等方面的智能化方向的趋势。 就目…

MySQL 字段为 NULL 的5大坑,大部分人踩过

数据库字段允许空值(null)的问题&#xff0c;小伙伴你遇到过吗&#xff1f; 在验证问题之前&#xff0c;我们先建一张测试表及测试数据。 构建的测试数据&#xff0c;如下图所示&#xff1a; 有了上面的表及数据之后&#xff0c;我们就来看当列中存在 NULL 值时&#xff0c;究…

基于RGB-D的6D目标检测算法

基于RGB-D的6D目标检测算法 本文参考了ITAIC的文章 A Review of 6D Object Pose Estimation 概览 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eQX8ke6j-1683188966051)(https://mezereon-upic.oss-cn-shanghai.aliyuncs.com/uPic/image-20230420…

如何理解信息化、数字化和智能化的概念?一文给你解惑!

如何理解信息化、数字化和智能化的概念&#xff1f; 前两年流行“信息化”&#xff0c;网上铺天盖地都是关于“信息化”的文章&#xff0c;这两年开始流行起“数字化”&#xff0c;于是铺天盖地都是“数字化”的文章&#xff0c;最近又开始大谈“智能化”...... 但点开那些文…

常见的5种项目管理问题类型

项目管理的5大影响素&#xff1a;时间、范围、成本、风险、质量。项目经理需要对这些因素进行均衡考量&#xff0c;并根据需要略有侧重&#xff0c;进行整体把握&#xff0c;即我们常说的均衡型管理风格。而忽略任何一因素&#xff0c;都会对项目产生极大影响。 常见的项目管理…

医院导诊图怎么做?目前比较好用的医院导航地图是哪一款?

现在很多的大医院&#xff0c;不只是越建越高&#xff0c;面积也越来越大&#xff0c;同时医院内部按照门诊、住院、放射等不同功能划分的区域也是越来越多&#xff0c;走进这些“超级医院”就像走进了迷宫一样&#xff0c;如何促使病患走进医院后&#xff0c;能迅速找到要去的…

19C RAC主库 to RAC备库搭建adg报错ORA-16047(修改19C RAC DB_UNIQUE_NAME )

文章目录 前言一、问题描述二、修改DB_UNIQUE_NAME1.查看集群配置2.将hip40实例从集群中移除3.修改db_unique_name4.将hip40dg实例添加到集群资源中5.重新启动实例 三、19C RAC 密码文件替换 前言 主库环境是19C RAC备库环境也是19C RAC&#xff0c;主库到备库做adg&#xff0…

移动端动态开发能力的由来和流派

移动端动态化的由来 “动态化”并不是最近几年才产生的名词&#xff0c;而是从从互联网诞生的初期&#xff0c;这个词就已经出现了。大家所认知的早期互联网&#xff0c;其实就是各种各类的“动态网站”&#xff0c;内容数据和页面外观都不是固定的&#xff0c;都是随着服务器…

Bash脚本中的Sleep命令到底有何妙用?

在编写Bash脚本时&#xff0c;有时需要在程序执行过程中加入一些等待时间&#xff0c;例如等待某个操作完成或等待某个进程退出。此时可以使用sleep命令来实现。 sleep命令可以让脚本暂停执行一段时间&#xff0c;其基本语法为&#xff1a; sleep <seconds>其中&#xf…

细数【SD-WEBUI】的模型:谁是最适合的模型从哪里找到它们

文章目录 &#xff08;零&#xff09;前言&#xff08;一&#xff09;基础模型&#xff08;Stable-Diffusion模型&#xff09;&#xff08;1.1&#xff09;ChilloutMix&#xff08;仿真&#xff09;&#xff08;1.2&#xff09;BasilMix&#xff08;仿真&#xff09;&#xff0…

如何使用 Linux Cron Job 优化WP-Cron以获得更好的性能

在本教程中&#xff0c;我将向您展示如何通过在 Linux 上用 Crontab 替换默认的 WP-Cron 触发机制来优化 WordPress 性能。 WordPress 使用 WP-Cron 来运行计划任务&#xff0c;许多用户已经在使用。 但它的工作方式并不理想。 在每次页面加载时&#xff0c;WP-Cron 检查计划…

在Centos7上安装和配置canal

1. 在 MySQL 数据库中创建 Canal 账户并为其授权 在安装 Canal 前&#xff0c;你需要在 MySQL 数据库中创建一个用于 Canal 连接的账户&#xff0c;并为该账户授予必要的权限。 以下是在 MySQL 数据库中创建 Canal 账户并为其授权的步骤&#xff1a; 登录 MySQL 使用以下命令…

B019_子查询篇

2022-4-30 18:11:32 通过本章学习,您将可以: 描述子查询可以解决的问题。 定义子查询。 列出子查询的类型。 书写单行子查询和多行子查询 MEGER INTO的使用 WITH 子句🏆CHAPTER 12 Subqueries & Merge Statements子查询和合并语句 子查询——嵌套在另一个查询中的查…

MyBatis:使用代码整合

文章目录 MyBatis&#xff1a;Day 04框架1. 依赖&#xff1a;pom.xml2. 外部配置文件&#xff1a;db.properties3. 核心配置文件&#xff1a;mybatis-config.xml4. 实体类5. 接口&#xff1a;xxxMapper.java6. 实现类&#xff1a;xxxMapper.xml7. 测试 MyBatis&#xff1a;Day …

DTC 2023回顾丨基于数据复制技术的多写多读数据库集群解决方案

在不久前结束的2023 DTC数据技术嘉年华中国数据库创新论坛上&#xff0c;GBASE南大通用8s产品经理郭茁老师分享了GBase 8s《基于数据复制技术的多写多读数据库集群解决方案》。 今天带大家一同回顾下本次演讲。 海量数据的存储和运算是目前行业内面临的一个重要问题&#xff0…

真实logging的构建

import logging import os.path import timeimport colorlog from logging.handlers import RotatingFileHandlerdefault_formats {# 终端输出格式color_format: %(log_color)s%(asctime)s-%(name)s-%(filename)s-[line:%(lineno)d]-%(levelname)s-[log-messge]: %(message)s,…

【Hydro】半图解法调洪演算步骤,附Python代码

说明 半图解法计算步骤如下: (1)根据水位&#xff5e;库容关系、水位&#xff5e;泄流关系以及计算时段等绘制辅助曲线&#xff1b; (2)确定起调水位 Z 1 Z_1 Z1​及相应的 q 1 q_1 q1​、 V 1 V_1 V1​计算各时段平均入库流量 Q p Q_p Qp​&#xff1b; (3)在水位坐标轴上确定…

使OpenGauss支持Python3存储过程

目录 一、概述 二、编译opengauss支持Python3存储过程 三、还有问题 一、概述 OpenGauss是可以支持以Python2、3编写存储过程的&#xff0c;但是这个功能默认不开启&#xff0c;想要这个功能要自己编译源码&#xff0c;目前这部分源码感觉不够成熟&#xff0c;还有一些问题&…

Linux必会100个命令(六十)curl

在Linux中curl是一个利用URL规则在命令行下工作的文件传输工具&#xff0c;可以说是一款很强大的http命令行工具。它支持文件的上传和下载&#xff0c;是综合传输工具。 curl选项比较多&#xff0c;使用man curl或者curl -h获取帮助信息。 -a/--append …