当前位置: 首页 > news >正文

[Java][算法 哈希]Day 01---LeetCode 热题 100---01~03

LeetCode 热题 100---01~03   ------->哈希

第一题  两数之和

思路

最直接的理解就是   找出两个数的和等于目标数   这两个数可以相同 但是不能是同一个数字(从数组上理解就是内存上不是同一位置)

解法一:暴力法

暴力解万物 按照需求  我们需要将数组的任意不同位置的数两两相加 再去判断是否等于目标数target 那么很显然 利用for循环的嵌套 第一层for循环从头遍历到尾 表示第一个数字 ;第二个数从第一个数的后一位置开始遍历到尾部,表示第二个数字

因为题目中明确说明了每种输入只会对应一个答案  所以找到之后就可以直接返回了

那么对应的代码就是

class Solution {public int[] twoSum(int[] nums, int target) {int n = nums.length;for (int i = 0; i < n; ++i) {for (int j = i + 1; j < n; ++j) {if (nums[i] + nums[j] == target) {return new int[]{i, j};}}}return new int[0];}
}

时间复杂度为O(N^2)

解法二:双指针法

上述时间复杂度之所以高 是因为我们查找第二个数采用的也是循环 就导致了循环的嵌套,如果想降低时间复杂度,那么就需要降低第二个数的查找时间

其实这个思路也比较简单 就是我们先将数组进行排序 保证从小到大/从大到小排序(这里我们排从小到大),那么 我们就可以最开始从数组最左侧A和最右侧B的两个数据开始相加得到sum  如果sum>target 那么说明我们需要讲两个加数变小,已知一个加数A已经是最小 那么只能让B往前走一位从而减小数据(当然 如果倒数第二个数据和最后一个数据等大  自然得出来的结果还是会大于target  但是不妨碍我们继续判断),反之  如果sum<target 那么就需要增大加数,只有加数A能够增大 所以就需要将加数A向右移动一位,依此类推,直到找到数据

class Solution {public int[] twoSum(int[] nums, int target) {ArrayList<Integer> list=new ArrayList<>();for (int num : nums) {list.add(num);}int[] dest = Arrays.copyOf(nums, nums.length);Arrays.sort(dest);int slow=0;int fast=nums.length-1;while(slow!=fast){int sum=dest[slow]+dest[fast];if(sum==target){int i = list.indexOf(dest[slow]);int j = list.lastIndexOf(dest[fast]);return new int[]{i,j};}else if(sum<target){slow++;}else if(sum>target){fast--;}}return new int[]{};}
}

可以看到  时间复杂度确实变小了  但是变化不多

解法三:哈希

这才是这个题目的出题本意  使用Hash来进行判断

同解法二,我们需要的是减少第二个数字的查询时间,我们可以将每个数存入Hash表中,然后通过target-A=B来得到B 然后判断在Hash表中是否存在B即可  因为Hash的缘故 第二个数据被查询的时间减少了

因为要找寻的是下表  我们利用Map数据结构 数据作为Key  下标作为Value  这样我们就可以通过key来找到下标

那么我们遍历一遍数组 作为第一个数A 然后通过containsKey(T   Key)方法来判断是否存在第二个数据B  如果存在 就直接通过get方法获得B的下标返回即可

如果不存在 就将该数放到Map中  之所以先判断后放入 是防止先放入之后  会出现自己和自己相加等于target的情况

class Solution {public int[] twoSum(int[] nums, int target) {Map<Integer, Integer> hashtable = new HashMap<Integer, Integer>();for (int i = 0; i < nums.length; ++i) {if (hashtable.containsKey(target - nums[i])) {return new int[]{hashtable.get(target - nums[i]), i};}hashtable.put(nums[i], i);}return new int[0];}
}

第二题  字母异位词分组

思路  

首先  字母异位词就是指  对一个单词重新排列顺序后 得到一个新的单词  在这个题目中  可以理解为  给你一个字符串数组  判断该数组中哪些元素是由同一些字母组成的 

例如示例一   eat  和 ate  和tea 三个元素都是由  a  e   t 组合而成 所以他们三个归为一个数组中

如此一来 我们只需要想办法  将各个方式组成的元素 用不重复方法标识出来即可 

最好的方法就是统计字母次数  

解法一:编码-分类

我们对每一个元素遍历  然后利用  每个单词-‘a’ 得到ASCII码差值  对应一个int[26] 数组arr中的每一个数据,简单理解就是a对应arr[0]  b对应arr[1]......以此类推  最后  由相同的字母组成的单词所得到的arr数据肯定相同  然后我们将arr转化为字符串String 作为标识的key  value采用List<String> 将同一类的单词都存入到这个Map<String,List<String>> map=new HashMap<>()中即可

class Solution {public List<List<String>> groupAnagrams(String[] strs) {List<List<String>> endList=new ArrayList<>();//最终返回的ListMap<String,List<String>> map=new HashMap<>();
// 遍历整个字符串数组进行操作for (String str : strs) {String code=getCode(str);  // 求出每个元素对应的code  作为标识key
// 判断该key是否存在 如果存在 就放到对应的List中 反之 如不存在 就创造一个新的key并new一个新List将该元素放入if(map.get(code)!=null){  map.get(code).add(str);}else{map.put(code,new ArrayList<>());map.get(code).add(str);}}
//最后遍历整个Map  将value取出来即可map.forEach((x,y)->endList.add(y));return endList;}public static String getCode(String str){char[] charArray = str.toCharArray();int [] arr=new int[26];for (char c : charArray) {arr[c-'a']++;}return Arrays.toString(arr);}
}

解法二:排序

如果两个单词是属于字母异位词,那么两者的字母组成肯定是相同的,如果字母组成是相同的,那么两者对内部单词进行同样的排序方式得到的结果也肯定是一样的,所以,我们需要对每个元素单词内部进行排序,然后将结果一样的放到一起即可

其实这种方法和上述的编码分类思想差不多,解法一是我们利用字母数量进行一个编码,我们解法二其实就是将排序后的结果作为标识编码来进行区分

class Solution {public static List<List<String>> groupAnagrams(String[] strs) {List<List<String>> endList=new ArrayList<>();Map<String,List<String>> map=new HashMap<String, List<String>>();for(String x:strs) {char[] arr=x.toCharArray();Arrays.sort(arr);String end=new String(arr);if(map.containsKey(end)) {map.get(end).add(x);}else {map.put(end,new ArrayList<String>());map.get(end).add(x);}}map.forEach((x,y)->{endList.add(y);});return endList;}
}

第三题 最长连续序列

思路

判断有无连续的序列,简单的方式就是遍历一遍,然后遍历每个数的时候,判断下一个数字是否等于前一个数字加一,等于的计数器+1,反之则归零

需要注意的是,需要考虑空数组,数组中存在相同元素的情况

解法一: 自己写的

我们自己的写法就是按照上述思路的遍历想法解题

class Solution {public int longestConsecutive(int[] nums) {if(nums.length==0) return 0; //空数组直接返回LinkedHashSet<Integer> temp = new LinkedHashSet<>();ArrayList<Integer> list=new ArrayList<>();
//我们需要set来去重  但是因为set本身是无序的  为了方便后续的比较后一位是否等于前一位加一
//就需要该集合是有序的  所以我们采用LinkedHashSet这种结构for(int x=0;x<nums.length;x++){temp.add(nums[x]);}
//去重后用List存储  方便转数组for (Integer i : temp) {list.add(i);}Integer[] array = list.toArray(new Integer[0]);int[] arr=new int[array.length];for (int i = 0; i < array.length; i++) {arr[i]=array[i];}int max=0;int number=0;Arrays.sort(arr);for (int i = 1; i < arr.length; i++) {
//遍历数组 判断前一位和后一位是否连续  连续+1  反之归零if(arr[i]==arr[i-1]+1){number++;}else{if(number>max){max=number;}number=0;}}if(number>max){max=number;}return max+1;}
}

可能会有疑问  为啥中间需要用List集合来转存一下 而不是直接Set集合temp转数组arr呢?其实也是可以的  对比两者 内存消耗和时间消耗其实差不多  temp直接转Array在某些特殊情况中会比List转Array是稍微多消耗一些资源的  所以哪怕第一段代码需要额外开销来转存到List中 但是单纯的开销空间来创造一个List和遍历集合消耗也不大

class Solution {public int longestConsecutive(int[] nums) {if(nums.length==0) return 0;LinkedHashSet<Integer> temp = new LinkedHashSet<>();for(int x=0;x<nums.length;x++){temp.add(nums[x]);}Integer[] array = temp.toArray(new Integer[0]);int[] arr=new int[array.length];for (int i = 0; i < array.length; i++) {arr[i]=array[i];}int max=0;int number=0;Arrays.sort(arr);for (int i = 1; i < arr.length; i++) {if(arr[i]==arr[i-1]+1){number++;}else{if(number>max){max=number;}number=0;}}if(number>max){max=number;}return max+1;}
}

解法二:官方解法---Hash法

官方解法还是很巧妙的,我们采取遍历的方式来找,很容易重复遍历判断相同序列

由于我们要枚举的数 x 一定是在数组中不存在前驱数 x−1 的,不然按照上面的分析我们会从 x−1x-1x−1 开始尝试匹配,因此我们每次在哈希表中检查是否存在 x−1即能判断是否需要跳过了。

增加了判断跳过的逻辑之后,时间复杂度是多少呢?外层循环需要 O(n) 的时间复杂度,只有当一个数是连续序列的第一个数的情况下才会进入内层循环,然后在内层循环中匹配连续序列中的数,因此数组中的每个数只会进入内层循环一次。根据上述分析可知,总时间复杂度为 O(n)符合题目要求。

class Solution {public int longestConsecutive(int[] nums) {Set<Integer> num_set = new HashSet<Integer>();for (int num : nums) {num_set.add(num);}int longestStreak = 0;for (int num : num_set) {if (!num_set.contains(num - 1)) {int currentNum = num;int currentStreak = 1;while (num_set.contains(currentNum + 1)) {currentNum += 1;currentStreak += 1;}longestStreak = Math.max(longestStreak, currentStreak);}}return longestStreak;}
}

相关文章:

[Java][算法 哈希]Day 01---LeetCode 热题 100---01~03

LeetCode 热题 100---01~03 ------->哈希 第一题 两数之和 思路 最直接的理解就是 找出两个数的和等于目标数 这两个数可以相同 但是不能是同一个数字&#xff08;从数组上理解就是内存上不是同一位置&#xff09; 解法一&#xff1a;暴力法 暴力解万物 按照需求 …...

【每日一题】LeetCode——链表的中间结点

&#x1f4da;博客主页&#xff1a;爱敲代码的小杨. ✨专栏&#xff1a;《Java SE语法》 | 《数据结构与算法》 | 《C生万物》 ❤️感谢大家点赞&#x1f44d;&#x1f3fb;收藏⭐评论✍&#x1f3fb;&#xff0c;您的三连就是我持续更新的动力❤️ &#x1f64f;小杨水平有…...

k8s 部署java应用 基于ingress+jar包

k8 集群ingress的访问模式 先部署一个namespace 命名空间 vim namespace.yaml kind: Namespace apiVersion: v1 metadata:name: ingress-testlabels:env: ingress-test 在部署deployment deployment是pod层一层封装。可以实现多节点部署 资源分配 回滚部署等方式。 部署的…...

深度学习技巧应用36-深度学习模型训练中的超参数调优指南大全,总结相关问题与答案

大家好,我是微学AI,今天给大家介绍一下深度学习技巧应用36-深度学习模型训练中的超参数调优指南大全,总结相关问题与答案。深度学习模型训练中的调优指南大全概括了数据预处理、模型架构设计、超参数优化、正则化策略和训练技巧等多个关键方面,以提升模型性能和泛化能力。 …...

“探索AJAX:前端与后端数据交互的利器“

前言 在现代Web开发中&#xff0c;前端与后端之间的数据交互是一个至关重要的环节。为了实现无需刷新页面的动态更新&#xff0c;AJAX&#xff08;Asynchronous JavaScript and XML&#xff09;作为一种强大的技术被广泛应用。 AJAX的原理 AJAX通过JavaScript和XMLHttpReque…...

【5G NR】移动通讯中使用的信道编解码技术

目录 一、引言 二、信道编解码技术概述 三、移动通讯中常用的信道编解码技术 四、优缺点分析与比较 五、未来发展趋势 六、结论 本文主要介绍了移动通讯中采用的信道编解码技术&#xff0c;由于在5G NR终端中&#xff0c;通常要兼容4G LTE通讯技术&#xff0c;所以4G LTE…...

用Python Tkinter打造的精彩连连看小游戏【附源码】

文章目录 连连看小游戏&#xff1a;用Python Tkinter打造的精彩游戏体验游戏简介技术背景MainWindow类:职责:方法:Point类: 主执行部分:完整代码&#xff1a;总结&#xff1a; 连连看小游戏&#xff1a;用Python Tkinter打造的精彩游戏体验 在丰富多彩的游戏世界中&#xff0c…...

nvm安装node后,npm无效

类似报这种问题&#xff0c;是因为去github下载npm时下载失败&#xff0c; Please visit https://github.com/npm/cli/releases/tag/v6.14.17 to download npm. 第一种方法&#xff1a;需要复制这里面的地址爬梯子去下载&#xff08;github有时不用梯子能直接下载&#xff0c;有…...

spring boot(2.4.x 开始)和spring cloud项目中配置文件application和bootstrap加载顺序

在前面的文章基础上 https://blog.csdn.net/zlpzlpzyd/article/details/136060312 spring boot 2.4.x 版本之前通过 ConfigFileApplicationListener 加载配置 https://github.com/spring-projects/spring-boot/blob/v2.3.12.RELEASE/spring-boot-project/spring-boot/src/mai…...

5-2、S曲线计算【51单片机+L298N步进电机系列教程】

↑↑↑点击上方【目录】&#xff0c;查看本系列全部文章 摘要&#xff1a;本节介绍S曲线的基本变换&#xff0c;将基本形式的S曲线变换成为任意过两点的S曲线&#xff0c;为后续步进电机S曲线运动提供理论支撑 一.计算目标 ①计算经过任意不同两点的S曲线方程 ②可调节曲线平…...

SQL 注入 - http头注入之UA头注入探测

环境准备:构建完善的安全渗透测试环境:推荐工具、资源和下载链接_渗透测试靶机下载-CSDN博客 一、http头注入介绍 HTTP头注入是一种网络安全攻击手段,它利用了Web应用程序对HTTP头的处理不当或缺乏充分的验证和过滤。在这种攻击中,攻击者通过修改HTTP请求头中的某些字段,…...

学习数据结构和算法的第5天

空间复杂度及其常见案例 空间复杂度 空间复杂度也是一个数学函数表达式&#xff0c;是对一个算法在运行过程中临时占用存储空间大小的量度。 空间复杂度不是程序占用了多少bytes的空间&#xff0c;因为这个也没太大意义&#xff0c;所以空间复杂度算的是变量的个数。空间复杂度…...

Android 11 访问 Android/data/或者getExternalCacheDir() root方式

前言&#xff1a; 需求要求安装三方应用ExternalCacheDir()下载下来的apk文件。 getExternalCacheDir() : /storage/emulated/0/Android/data/com../cache/ 获取访问权限 如果手机安卓版本为Android10的时候,可以在AndroidManifest.xml中添加下列代码 android:requestLegacyExt…...

Linux探秘之旅:透彻理解路径、命令与系统概念

目录 如何远程连接 远程登录简明指南 linux区别 1.严格区分大小写 2.linux的命令返回结果判断 3.如何查看网络信息 4.关于后缀名&#xff08;Linux不关心文件后缀&#xff09; 4.1 需要记忆的后缀 5.echo命令 6.linux一切皆文件 6.1比如磁盘的文件 6.2可执行文件 …...

哈希算法 c语言

#include <stdio.h> #include <stdlib.h> #include <string.h> // 哈希函数 unsigned int hash_function(const char *str) { unsigned int hash 0; while (*str) { hash (hash * 31 *str) % 1000; str; } return hash;…...

新版MQL语言程序设计:组合模式的原理、应用及代码实现

文章目录 一、什么组合模式二、为什么需要组合模式三、组合模式的实现原理四、组合模式的应用场景五、组合模式的代码实现 一、什么组合模式 组合模式是一种结构型设计模式&#xff0c;它允许将对象组合成树形结构以表示“部分-整体”的层次结构。组合模式使得用户对单个对象和…...

代码随想录算法训练营第25天 | 216.组合总和III ,17.电话号码的字母组合

回溯章节理论基础&#xff1a; https://programmercarl.com/%E5%9B%9E%E6%BA%AF%E7%AE%97%E6%B3%95%E7%90%86%E8%AE%BA%E5%9F%BA%E7%A1%80.html 216.组合总和III 题目链接&#xff1a;https://leetcode.cn/problems/combination-sum-iii/ 思路: 本题就是在[1,2,3,4,5,6,7,…...

Rust 第一个rust程序Hello Rust️

文章目录 前言一、vscode 安装rust相关插件二、Cargo New三、vscode调试rustLLDB 前言 Rust学习系列。今天就让我们掌握第一个rust程序。Hello Rust &#x1f980;️。 在上一篇文章我们在macOS成功安装了rust。 一、vscode 安装rust相关插件 以下是一些常用的 Rust 开发插件…...

高斯消去法 | LU分解 | PA=LU分解(MatLab)

一、问题描述 利用高斯消去法&#xff0c;LU 分解及PALU 分解求解非线性方程组。 二、实验目的 掌握高斯消去法、LU 分解、PALU 分解的算法原理&#xff1b;编写代码实现利用高斯消去法、LU 分解、PALU 分解来求解线性方程组。 三、实验内容及要求 1. 利用顺序高斯消去法求…...

Linux笔记之expect和bash脚本监听输出并在匹配到指定字符串时发送中断信号

Linux笔记之expect和bash脚本监听输出并在匹配到指定字符串时发送中断信号 code review! 文章目录 Linux笔记之expect和bash脚本监听输出并在匹配到指定字符串时发送中断信号1.expect2.bash 1.expect 在Expect脚本中&#xff0c;你可以使用expect来监听程序输出&#xff0c;…...

FFmpeg 低延迟同屏方案

引言 在实时互动需求激增的当下&#xff0c;无论是在线教育中的师生同屏演示、远程办公的屏幕共享协作&#xff0c;还是游戏直播的画面实时传输&#xff0c;低延迟同屏已成为保障用户体验的核心指标。FFmpeg 作为一款功能强大的多媒体框架&#xff0c;凭借其灵活的编解码、数据…...

Day131 | 灵神 | 回溯算法 | 子集型 子集

Day131 | 灵神 | 回溯算法 | 子集型 子集 78.子集 78. 子集 - 力扣&#xff08;LeetCode&#xff09; 思路&#xff1a; 笔者写过很多次这道题了&#xff0c;不想写题解了&#xff0c;大家看灵神讲解吧 回溯算法套路①子集型回溯【基础算法精讲 14】_哔哩哔哩_bilibili 完…...

Swift 协议扩展精进之路:解决 CoreData 托管实体子类的类型不匹配问题(下)

概述 在 Swift 开发语言中&#xff0c;各位秃头小码农们可以充分利用语法本身所带来的便利去劈荆斩棘。我们还可以恣意利用泛型、协议关联类型和协议扩展来进一步简化和优化我们复杂的代码需求。 不过&#xff0c;在涉及到多个子类派生于基类进行多态模拟的场景下&#xff0c;…...

ESP32读取DHT11温湿度数据

芯片&#xff1a;ESP32 环境&#xff1a;Arduino 一、安装DHT11传感器库 红框的库&#xff0c;别安装错了 二、代码 注意&#xff0c;DATA口要连接在D15上 #include "DHT.h" // 包含DHT库#define DHTPIN 15 // 定义DHT11数据引脚连接到ESP32的GPIO15 #define D…...

SpringBoot+uniapp 的 Champion 俱乐部微信小程序设计与实现,论文初版实现

摘要 本论文旨在设计并实现基于 SpringBoot 和 uniapp 的 Champion 俱乐部微信小程序&#xff0c;以满足俱乐部线上活动推广、会员管理、社交互动等需求。通过 SpringBoot 搭建后端服务&#xff0c;提供稳定高效的数据处理与业务逻辑支持&#xff1b;利用 uniapp 实现跨平台前…...

Springcloud:Eureka 高可用集群搭建实战(服务注册与发现的底层原理与避坑指南)

引言&#xff1a;为什么 Eureka 依然是存量系统的核心&#xff1f; 尽管 Nacos 等新注册中心崛起&#xff0c;但金融、电力等保守行业仍有大量系统运行在 Eureka 上。理解其高可用设计与自我保护机制&#xff0c;是保障分布式系统稳定的必修课。本文将手把手带你搭建生产级 Eur…...

Spring数据访问模块设计

前面我们已经完成了IoC和web模块的设计&#xff0c;聪明的码友立马就知道了&#xff0c;该到数据访问模块了&#xff0c;要不就这俩玩个6啊&#xff0c;查库势在必行&#xff0c;至此&#xff0c;它来了。 一、核心设计理念 1、痛点在哪 应用离不开数据&#xff08;数据库、No…...

JAVA后端开发——多租户

数据隔离是多租户系统中的核心概念&#xff0c;确保一个租户&#xff08;在这个系统中可能是一个公司或一个独立的客户&#xff09;的数据对其他租户是不可见的。在 RuoYi 框架&#xff08;您当前项目所使用的基础框架&#xff09;中&#xff0c;这通常是通过在数据表中增加一个…...

windows系统MySQL安装文档

概览&#xff1a;本文讨论了MySQL的安装、使用过程中涉及的解压、配置、初始化、注册服务、启动、修改密码、登录、退出以及卸载等相关内容&#xff0c;为学习者提供全面的操作指导。关键要点包括&#xff1a; 解压 &#xff1a;下载完成后解压压缩包&#xff0c;得到MySQL 8.…...

Qt 事件处理中 return 的深入解析

Qt 事件处理中 return 的深入解析 在 Qt 事件处理中&#xff0c;return 语句的使用是另一个关键概念&#xff0c;它与 event->accept()/event->ignore() 密切相关但作用不同。让我们详细分析一下它们之间的关系和工作原理。 核心区别&#xff1a;不同层级的事件处理 方…...