算法打卡day5|哈希表篇01|Leetcode 242.有效的字母异位词 、19.删除链表的倒数第N个节点、202. 快乐数、1. 两数之和

哈希表基础知识

哈希表

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

般哈希表都是用来快速判断一个元素是否出现集合里。例如要查询一个名字是否在班级里:

要枚举的话时间复杂度是O(n),但如果使用哈希表的话, 只需要O(1);

哈希函数

把学生的姓名直接映射为哈希表上的索引,然后就可以通过查询索引下标快速知道这位同学是否在这所学校里了。哈希函数如下图所示,通过hashCode名字转化为数值,一般hashcode是通过特定编码方式,可以将其他数据格式转化为不同的数值,这样就把学生名字映射为哈希表上的索引数字了。

哈希表2

如果hashCode得到的数值大于 哈希表的大小了,此时为了保证映射出来的索引数值都落在哈希表上,会在再次对数值做一个取模的操作,这样我们就保证了学生姓名一定可以映射到哈希表上了。

但就算哈希函数计算的再均匀,也避免不了会有几位学生的名字同时映射到哈希表 同一个索引下标的位置。这就造成了哈希碰撞

哈希碰撞

如图所示,小李和小王都映射到了索引下标 1 的位置,这一现象叫做哈希碰撞

哈希表3

一般哈希碰撞有两种解决方法, 拉链法和线性探测法。

拉链法

当小李和小王在索引1的位置发生了冲突,发生冲突的元素都被存储在链表中。 这样我们就可以通过索引找到小李和小王了;(数据规模是dataSize, 哈希表的大小为tableSize)

哈希表4

线性探测法

使用线性探测法,一定要保证tableSize大于dataSize。 我们需要依靠哈希表中的空位来解决碰撞问题。

例如冲突的位置,放了小李,那么就向下找一个空位放置小王的信息。所以要求tableSize一定要大于dataSize ,要不然哈希表上就没有空置的位置来存放 冲突的数据了。如图所示:

哈希表5

常见的三种哈希结构

 在Java中,哈希结构是一种基于哈希表的数据结构,主要用于快速查找和存取数据。常见的哈希结构包括数组、集合和映射。以下是它们的定义、特性以及使用场景的介绍。

数组(Array)

定义:数组是一种线性数据结构,用于存储固定数量的同类型元素。它提供了通过索引快速访问元素的能力。
特性:数组的大小在创建时就已确定,且之后不能改变。数组在内存中连续分配空间,这有助于快速访问元素。
使用场景:当你需要快速随机访问元素并且知道元素的数量时,数组是一个不错的选择。例如,处理固定大小的列表、缓冲区或矩阵。

集合(Collection)
 

定义:集合是Java集合框架的一部分,它提供了一组接口和类,用于存储和操作一组对象。集合框架包括List、Set等多种类型。

特性:集合框架提供了丰富的操作,如添加、删除、遍历元素等。集合可以动态增长和缩小,不需要预先指定大小。

使用场景:集合适用于存储和管理一组对象的场景,尤其是当对象的数量未知或可能变化时。例如,存储用户列表、日志消息或任何动态集合的数据。

映射(Map)

定义:映射是一种键值对的集合,它允许通过唯一的键快速检索值。Java中的Map接口及其实现类(如HashMap、TreeMap等)提供了这种功能。

特性:每个键最多映射到一个值,键不能重复。映射提供了快速的查找、插入和删除操作。

使用场景:映射适用于需要通过键来快速检索值的场景。例如,在数据库查询结果映射、实现属性文件解析、缓存数据等方面非常有用。

算法题

Leetcode   242.有效的字母异位词 

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

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

个人思路

利用哈希表结构,先遍历一遍a存字符数量到辅助数组,然后再遍历一遍b查值并删除对应字符数量,最后遍历一遍这个辅助数组,如果有字符数量不为0,则不为异位词。

解法
哈希数组

定义一个数组叫做help用来上记录字符串s里字符出现的次数。因为只包括小写字母,所以直接字符a映射为下标0,相应的字符z映射为下标25。再遍历 字符串s的时候,只需要将 s[i] - ‘a’ 所在的元素做+1 操作即可,就能求出一个字母对应出现次数 然后在遍历字符串t 的时候,对t中出现的字符映射哈希表索引上的数值做-1的操作。那么最后检查一下,help数组如果有的元素不为零0,说明字符串s和t一定是谁多了字符或者谁少了字符。最后如果help数组所有元素都为零0,说明字符串s和t是字母异位词,return true。

class Solution {
    public boolean isAnagram(String s, String t) {
        int[] help=new int[26];//辅助数组
        for(int i =0;i<s.length();i++){ // 求出字符串s对应字母的存在个数
            help[s.charAt(i) -'a'] ++;
        }

        for(int i =0;i<t.length();i++){
            help[t.charAt(i) -'a'] --;
        }

        for(int i=0;i<help.length;i++){ 
            // help数组如果有的元素不为零0,说明字符串s和t 一定是谁多了字符或者谁少了字符。
            if(help[i]!=0){
                return false;
            }
        }
        return true; // help数组所有元素都为零0,说明字符串s和t是字母异位词
    }
}

时间复杂度:O(nlog n);(3个for循环)

空间复杂度:O(1);(没常量大小的辅助数组)

Leetcode 349. 两个数组的交集 

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

大佬视频讲解:两个数组之间的交集视频讲解

个人思路

因为结果要求不重复,那可以用set集合;先用一个hashSet存取数组1的值,再看这个hashSet中是否包含数组2的值,如果包含则将数字放入结果集中;

解法
哈希集合

这道题目没有限制数值的大小,就无法使用数组来做哈希表了。而且如果哈希值比较少、特别分散、跨度非常大,使用数组就造成空间的极大浪费

但如果所有题目都直接使用set 不仅占用空间比数组大,而且速度要比数组慢,set把数值映射到key上都要做hash计算的。在数据量大的情况,差距是非常明显的。

class Solution {
    public int[] intersection(int[] nums1, int[] nums2) {
    //nums1 == null判断数组引用是否被初始化
    //nums1.length == 0 判断数组已经初始化后是否有元素
       if(nums1 == null || nums1.length == 0 || nums1 == null || nums1.length == 0 ){
           return new int[0];
       }
      Set<Integer>  setNum1=new HashSet<>();
      Set<Integer>  result=new HashSet<>();

       for(int i=0;i<nums1.length;i++){//遍历数组1存值
           setNum1.add(nums1[i]);
       }

       for(int num:nums2){ //遍历数组2的过程中判断哈希表中是否存在该元素
           if(setNum1.contains(num)){
               result.add(num);
           }
       }
       return result.stream().mapToInt(x -> x).toArray();//将结果集合转为数组
    }
}
//最后return的数组,也可以另外申请一个数组存放setRes中的元素
        int[] arr = new int[resSet.size()];
        int j = 0;
        for(int i : resSet){
            arr[j++] = i;
        }

时间复杂度:O(n);(两个不嵌套的for循环)

空间复杂度:O(n);(使用多两个set)

Leetcode  202. 快乐数

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

个人思路

快乐数中一个很重要的定义,平方和就是不能重复,否则会无限循环;那可以使用hashSet来解决这道题。

解法
哈希集合

当遇到了要快速判断一个元素是否出现集合里的时候,就要考虑哈希法。所以这道题目使用哈希法,来判断这个sum是否重复出现,如果重复了就是return false, 否则一直找到sum为1为止。

class Solution {
    public boolean isHappy(int n) {
        Set<Integer> res=new HashSet<>();
        //1本身就是快乐数
        //这个过程结果不能重复出现,不然会无限循环;
        while(n!=1 && !res.contains(n)){
            res.add(n);
            n=comput(n);//计算每个位置上的平方和
        }
        return n==1;
    }

    public int comput(int n){
        int sum=0;
        while(n>0){
            int temp= n%10;//求余数
            sum+=temp*temp;//累加平方和
            n=n/10;//从个位到十位到百位到...
        }
        return sum;
    }
}

时间复杂度:O( n);(模内层循环comput,对于每个n,它会执行n次,因为它是对n的每一位数字进行平方然后求和)

空间复杂度:O(n);( 在最坏的情况下,HashSet可能会存储所有小于等于n的数字,因此空间复杂度为O(n))

Leetcode 1. 两数之和 

题目链接:1. 两数之和 

 大佬视频讲解:两数之和 视频讲解

个人思路

因为既要求下标,又要求值,可以考虑使用哈希映射这个结构;

解法
哈希映射

在使用map时要明确两点:

1.map用来做什么

map目的用来存放我们访问过的元素,因为遍历数组的时候,需要记录我们之前遍历过哪些元素和对应的下标,这样才能找到与当前元素相匹配的(也就是相加等于target)

2.map中key和value分别表示什么

因为需要判断元素是否出现,还要真的元素的下标,所以 map中的存储结构为 {key:数据元素,value:数组元素对应的下标}。

然后在遍历数组的时候,只需要向map去查询是否有和目前遍历元素匹配的数值,如果有,就找到的匹配对,如果没有,就把目前遍历的元素放进map中;

class Solution {
    public int[] twoSum(int[] nums, int target) {
        int[] res=new int[2]; 
        //nums == null判断数组引用是否被初始化
        //nums.length == 0 判断数组已经初始化后是否有元素
        if(nums==null || nums.length==0){
            return res;
        }
        Map<Integer,Integer> mapX=new HashMap<>();//key存数组值,value存数组下标
        for(int i=0;i<nums.length;i++){
            int temp=target-nums[i];
            if(mapX.containsKey(temp)){// 遍历当前元素,并在map中寻找是否有匹配的key
                res[0]=i;
                res[1]=mapX.get(temp);
                break;
            }
            mapX.put(nums[i],i); // 如果没找到匹配对,就把访问过的元素和下标加入到map中
        }
        return res;
    }
}

时间复杂度:O(n);(一个for循环)

空间复杂度:O(n);(使用map)

以上是个人的思考反思与总结,若只想根据系列题刷,参考卡哥的网址代码随想录算法官网

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【开源】JAVA+Vue.js实现天沐瑜伽馆管理系统

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 数据中心模块2.2 瑜伽课程模块2.3 课程预约模块2.4 系统公告模块2.5 课程评价模块2.6 瑜伽器械模块 三、系统设计3.1 实体类设计3.1.1 瑜伽课程3.1.2 瑜伽课程预约3.1.3 系统公告3.1.4 瑜伽课程评价 3.2 数据库设计3.2.…

【C语言】动态内存管理常用函数

前言 我们在之前学习的数组开辟的空间是固定不变的&#xff0c;有时候我们需要的空间⼤⼩在程序运⾏的时候才能知道~ c语言中的动态内存开辟&#xff0c;让程序员⾃⼰可以根据实际需求申请和释放相应空间&#xff0c;这使得空间的开辟变得灵活了许多。 欢迎关注个人主页&#x…

【C++进阶】哈希表的闭散列和开散列(哈希桶)的代码实现

&#x1f466;个人主页&#xff1a;Weraphael ✍&#x1f3fb;作者简介&#xff1a;目前学习C和算法 ✈️专栏&#xff1a;C航路 &#x1f40b; 希望大家多多支持&#xff0c;咱一起进步&#xff01;&#x1f601; 如果文章对你有帮助的话 欢迎 评论&#x1f4ac; 点赞&#x1…

mariadb数据库——安装,创建数据库

MariaDB是一个流行的开源关系型数据库管理系统&#xff08;RDBMS&#xff09;&#xff0c;它是MySQL的一个分支。 安装 apt -y install mariadb-servervi /etc/mysql/mariadb.conf.d/50-server.cnf character-set-server utf8mb4 collation-server utf8mb4_general_c…

什么时候要用到Reflect API?

参考文档 https://www.zhihu.com/question/460133198 https://cn.vuejs.org/guide/extras/reactivity-in-depth.html https://juejin.cn/post/7103764386220769311 Reflect API 一般搭配 Proxy API 一起使用。什么是 Proxy API 呢&#xff1f; 先回顾下 vue 的数据响应性是如何…

【已解决】卸载软件时显示“无法使用此产品的安装源,请确认安装源存在,并且你可以访问它”报错截图如下

卸载软件时显示“无法使用此产品的安装源&#xff0c;请确认安装源存在&#xff0c;并且你可以访问它”报错截图如下 使用Uninstall Tool软件强制删除&#xff0c;绕过软件自带的uninstall程序。&#xff08;小白推荐&#xff0c;如下图&#xff09; Uninstall Tool - Unique…

【DAY06 软考中级备考笔记】数据结构:树

数据结构&#xff1a;树 3月1日 – 天气&#xff1a;晴 之前在B站看的视频讲的是在太过简单&#xff0c;弃了。现在换了新的视频继续&#xff0c;后续会重新看前面的视频补过来。https://www.bilibili.com/video/BV1pT4m1S7uH/ 1. 树的基本概念 需要注意的是&#xff1a; 并不是…

代码随想录算法训练营第五天

● 自己看到题目的第一想法 242. 有效的字母异位词 方法&#xff1a; 方法一&#xff1a; 暴力法 1. 分别对s, t排序 2. 遍历s与t 判断s[i]!t[i] 返回 false 否则 返回true思路&#xff1a; 注意&#xff1a; 代码&#xff1a; bool cmp(char a, char b){return a<b;…

解决GitHub无法访问的问题:手动修改hosts文件与使用SwitchHosts工具

✨✨ 欢迎大家来访Srlua的博文&#xff08;づ&#xffe3;3&#xffe3;&#xff09;づ╭❤&#xff5e;✨✨ &#x1f31f;&#x1f31f; 欢迎各位亲爱的读者&#xff0c;感谢你们抽出宝贵的时间来阅读我的文章。 我是Srlua&#xff0c;在这里我会分享我的知识和经验。&#x…

Node.js+Express后端,自定义接口

6分钟学会Express 后端 API 开发 Node.js 2020最新版_哔哩哔哩_bilibili 要使用Node.js和Express搭建一个简单的后台服务器&#xff0c;用于接收带有token的请求头&#xff0c;你可以按照以下步骤进行操作&#xff1a; 首先&#xff0c;确保你已经安装了Node.js和npm&#xff0…

OpenAI员工自曝996作息表,网友:真正的卷不需要强迫

鱼羊 发自 凹非寺 量子位 | 公众号 QbitAI OpenAI也996&#xff0c;实锤了&#xff08;doge&#xff09;。 思维链作者、从谷歌跳槽OpenAI的Jason Wei刚刚分享了自己在OpenAI的一天&#xff1a; [9:00am] 起床 [9:30am] 搭乘Waymo前往Mission SF&#xff0c;途中在Tartine买…

一篇文章带你搞定企业级完整性能测试流程

大部分公司在最初试的阶段只会关心项目的基本功能&#xff0c;能用就可以。但是随着项目的成熟&#xff0c;用户量逐步的增大&#xff0c;线上经常就会出现一些系统崩溃&#xff0c;用户反映系统太慢等性能问题的爆发。所以&#xff0c;性能测试的需求就逐步变得迫切了。所以&a…

【笔记】深度学习入门:基于Python的理论与实现(六)

深度学习 深度学习是加深了层的深度神经网络 加深网络 本节我们将这些已经学过的技术汇总起来&#xff0c;创建一个深度网络&#xff0c;挑战 MNIST 数据集的手写数字识别 向更深的网络出发 基于33的小型滤波器的卷积层。激活函数是ReLU。全连接层的后面使用Dropout层。基…

varFormatter 数据格式化库 以性能优先的 快速的 内存对象格式转换

varFormatter 数据格式化 技术 开源技术栏 对象/变量格式化工具库&#xff0c;其支持将一个对象进行按照 JSON XML HTML 等格式进行转换&#xff0c;并获取到结果字符串&#xff01; 目录 文章目录 varFormatter 数据格式化 技术目录介绍获取方式 使用实例格式化组件的基本使…

【C++初阶】内存管理

目录 一.C语言中的动态内存管理方式 二.C中的内存管理方式 1.new/delete操作内置类型 2.new和delete操作自定义类型 3.浅识抛异常 &#xff08;内存申请失败&#xff09; 4.new和delete操作自定义类型 三.new和delete的实现原理 1.内置类型 2.自定义类型 一.C语…

电机应用-正点原子直流有刷电机例程笔记

目录 基础驱动实验&#xff1a;调速和换向 初始化工作 电机基础驱动API 电压、电流、温度检测实验 初始化工作 采集工作 编码器测速实验 编码器接口计数原理 初始化工作 编码器测速工作 速度环控制实现 PID相关函数 PID运算 电流环控制实现 PID相关函数 PID运算…

代码随想录算法训练营第三十三天|1005.K次取反后最大化的数组和、134. 加油站、135. 分发糖果

1005.K次取反后最大化的数组和 刷题https://leetcode.cn/problems/maximize-sum-of-array-after-k-negations/description/文章讲解https://programmercarl.com/1005.K%E6%AC%A1%E5%8F%96%E5%8F%8D%E5%90%8E%E6%9C%80%E5%A4%A7%E5%8C%96%E7%9A%84%E6%95%B0%E7%BB%84%E5%92%8C.…

iOS-设置指定边圆角(左上、左下等)

以UILabel举例&#xff0c;效果图如下&#xff1a; 代码如下&#xff1a; //设置左上与右下圆角&#xff08;可自行编辑指定圆角位置&#xff09; UIBezierPath *maskPath [UIBezierPath bezierPathWithRoundedRect:_sleepStateLabel.bounds byRoundingCorners:UIRectCornerT…

Python 全栈系列227 部署chatglm3-API接口

说明 上一篇介绍了基于算力租用的方式部署chatglm3, 见文章&#xff1b;本篇接着看如何使用API方式进行使用。 内容 1 官方接口 详情可见接口调用文档 调用有两种方式&#xff0c;SDK包和Http。一般来说&#xff0c;用SDK会省事一些。 以下是Python SDK包的git项目地址 安…

“环波罗的海”包围圈将正式形成

据“直新闻”的消息称&#xff0c;近日匈牙利国会同意了瑞典加入北约的申请&#xff0c;在走完相关后续程序后&#xff0c;瑞典就将成为北约第三十二个成员国&#xff0c;而北约对俄罗斯打造的“环波罗的海”包围圈也将正式形成&#xff0c;即除俄方外&#xff0c;波罗的海周边…