当前位置: 首页 > 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;…...

高频面试之3Zookeeper

高频面试之3Zookeeper 文章目录 高频面试之3Zookeeper3.1 常用命令3.2 选举机制3.3 Zookeeper符合法则中哪两个&#xff1f;3.4 Zookeeper脑裂3.5 Zookeeper用来干嘛了 3.1 常用命令 ls、get、create、delete、deleteall3.2 选举机制 半数机制&#xff08;过半机制&#xff0…...

零基础设计模式——行为型模式 - 责任链模式

第四部分&#xff1a;行为型模式 - 责任链模式 (Chain of Responsibility Pattern) 欢迎来到行为型模式的学习&#xff01;行为型模式关注对象之间的职责分配、算法封装和对象间的交互。我们将学习的第一个行为型模式是责任链模式。 核心思想&#xff1a;使多个对象都有机会处…...

ArcGIS Pro制作水平横向图例+多级标注

今天介绍下载ArcGIS Pro中如何设置水平横向图例。 之前我们介绍了ArcGIS的横向图例制作&#xff1a;ArcGIS横向、多列图例、顺序重排、符号居中、批量更改图例符号等等&#xff08;ArcGIS出图图例8大技巧&#xff09;&#xff0c;那这次我们看看ArcGIS Pro如何更加快捷的操作。…...

力扣热题100 k个一组反转链表题解

题目: 代码: func reverseKGroup(head *ListNode, k int) *ListNode {cur : headfor i : 0; i < k; i {if cur nil {return head}cur cur.Next}newHead : reverse(head, cur)head.Next reverseKGroup(cur, k)return newHead }func reverse(start, end *ListNode) *ListN…...

加密通信 + 行为分析:运营商行业安全防御体系重构

在数字经济蓬勃发展的时代&#xff0c;运营商作为信息通信网络的核心枢纽&#xff0c;承载着海量用户数据与关键业务传输&#xff0c;其安全防御体系的可靠性直接关乎国家安全、社会稳定与企业发展。随着网络攻击手段的不断升级&#xff0c;传统安全防护体系逐渐暴露出局限性&a…...

Python 高级应用10:在python 大型项目中 FastAPI 和 Django 的相互配合

无论是python&#xff0c;或者java 的大型项目中&#xff0c;都会涉及到 自身平台微服务之间的相互调用&#xff0c;以及和第三发平台的 接口对接&#xff0c;那在python 中是怎么实现的呢&#xff1f; 在 Python Web 开发中&#xff0c;FastAPI 和 Django 是两个重要但定位不…...

网页端 js 读取发票里的二维码信息(图片和PDF格式)

起因 为了实现在报销流程中&#xff0c;发票不能重用的限制&#xff0c;发票上传后&#xff0c;希望能读出发票号&#xff0c;并记录发票号已用&#xff0c;下次不再可用于报销。 基于上面的需求&#xff0c;研究了OCR 的方式和读PDF的方式&#xff0c;实际是可行的&#xff…...

手动给中文分词和 直接用神经网络RNN做有什么区别

手动分词和基于神经网络&#xff08;如 RNN&#xff09;的自动分词在原理、实现方式和效果上有显著差异&#xff0c;以下是核心对比&#xff1a; 1. 实现原理对比 对比维度手动分词&#xff08;规则 / 词典驱动&#xff09;神经网络 RNN 分词&#xff08;数据驱动&#xff09…...

PostgreSQL 与 SQL 基础:为 Fast API 打下数据基础

在构建任何动态、数据驱动的Web API时&#xff0c;一个稳定高效的数据存储方案是不可或缺的。对于使用Python FastAPI的开发者来说&#xff0c;深入理解关系型数据库的工作原理、掌握SQL这门与数据库“对话”的语言&#xff0c;以及学会如何在Python中操作数据库&#xff0c;是…...

统计按位或能得到最大值的子集数目

我们先来看题目描述&#xff1a; 给你一个整数数组 nums &#xff0c;请你找出 nums 子集 按位或 可能得到的 最大值 &#xff0c;并返回按位或能得到最大值的 不同非空子集的数目 。 如果数组 a 可以由数组 b 删除一些元素&#xff08;或不删除&#xff09;得到&#xff0c;…...