【牛客网-面试必刷TOP 101】01链表

BM1 反转链表
解题思路
第一种方法:借助栈
1. 栈的特点是先进后出,用stack来存储链表,之后新建一个头节点,按出栈顺序拼接形成新的链表。
2. 注意,最后一个节点的next要赋值null
3. 空间复杂度O(N), 时间复杂度O(N)

JAVA代码实现

import java.util.*;
public class Solution {public ListNode ReverseList (ListNode head) {// 用栈,空间复杂度O(N),时间复杂度O(N)Stack<ListNode> stack = new Stack<>();while(head != null){stack.push(head);head = head.next;}//出栈,重新连接if(stack.isEmpty()){return null;}ListNode node = stack.pop();ListNode dummy = node;while(!stack.isEmpty()){ListNode tempNode = stack.pop();node.next = tempNode;node = node.next;}//最后一个下一位为空node.next = null;return dummy;}
}

在这里插入图片描述

第二种方法,修改链表指针指向;
指针cur表示当前要处理的节点
指针tmp用于暂存cur.next,避免后面修改指针后,断链无法继续遍历
指针pre表示当前处理节点的上一个节点,进行翻转的目的是将cur.next修改成pre
初始化时,我们将pre设为null,因为第一个节点最后变成最后一个节点,其next为null
import java.util.*;
public class Solution {public ListNode ReverseList (ListNode head) {//双指针迭代,空间复杂度O(1),时间复杂度O(N)//前继节点为pre,当前操作节点为cur//初始化cur为head,pre=nullListNode cur = head, pre = null;while(cur != null){ListNode nextNode = cur.next;//存储下一个节点,不然局部反转的时候会断链cur.next = pre;pre = cur;cur = nextNode;}return pre;}
}
BM2 链表内指定区间反转
解题思路
在上一题的基础上进行修改
首先,要处理的cur节点先走m步走到第m个节点
反转结束的条件不是链表遍历到末尾null时候,而是遍历到第n个节点就结束
没有结束额外空间,空间复杂度O(1), 时间复杂度O(N)
import java.util.*;
public class Solution {public ListNode reverseBetween (ListNode head, int m, int n) {// write code here//可以用BM1 反转链表的思想,ListNode  dummy = new ListNode(-1);dummy.next = head;ListNode pre = dummy;ListNode cur = head;//找mfor (int i = 1; i < m; ++i) {pre = cur;cur = cur.next;}//反转m到nfor (int i = m; i < n; ++i) {ListNode temp = cur.next;cur.next = temp.next;temp.next = pre.next;pre.next = temp;}return dummy.next;}
}
BM3 链表中的节点每k个一组翻转
解题思路
参考了官方解题,递归翻转
设置一个遍历的尾指针tail,每次反转之前找到翻转区间的最后一个节点
如果tail在k步内变成了null,则直接返回,不进行翻转(最后一段不足k个,不翻转)
之后与BM1一样,定义pre,cur,翻转结束的条件是当走到tail,停止翻转
递归的返回值是当前翻转这一分组的头结点
这道题还不是很理解,后面有新的理解再重新整理笔记
import java.util.*;
public class Solution {public ListNode reverseKGroup (ListNode head, int k) {// write code hereListNode tail = head;//反转的尾部//遍历k次到尾部for (int i = 0; i < k; ++i) {//如果不足k到了尾部,则不翻转if (tail == null) {return head;}tail = tail.next;}ListNode pre = null;ListNode cur = head;while (cur != tail) {//到达尾部前ListNode temp = cur.next;cur.next = pre;pre = cur;cur = temp;}//当前尾指向下一段要翻转的链表head.next = reverseKGroup(tail,k);return pre;}
}
BM4 合并两个排序的链表
解题思路
比较简单,新建一个链表,同时遍历两个链表,比较val的大小,遇到较小的就加入;
import java.util.*;
public class Solution {public ListNode Merge (ListNode pHead1, ListNode pHead2) {// write code hereListNode res = new ListNode(-1);ListNode dummy = res;while(pHead1 != null && pHead2 != null){if(pHead1.val <= pHead2.val){dummy.next = pHead1;pHead1 = pHead1.next;}else{dummy.next = pHead2;pHead2 = pHead2.next;}dummy = dummy.next;}if(pHead1 != null){dummy.next = pHead1;}if(pHead2 != null){dummy.next = pHead2;}return res.next;}
}
BM6 判断链表中是否有环
解题思路
是的,没有BM5,因为它是难题,菜的一批的我看答案也还没理解透
利用双指针,slow每次往前走一步,fast每次往前走两步,如果链表中有环,则两个指针最终会在非终点的地方相遇
因为地球是圆的,slow和fast不是平行走,总会在一个时间点遇到的,时长的问题而已     
双指针在后面很多题目中都会遇到过。
import java.util.*;
public class Solution {public boolean hasCycle(ListNode head) {//快慢指针ListNode fast = head;ListNode slow = head;if(head == null){return false;}// fast.next = head;// slow.next = head;while(fast != null && fast.next != null){fast = fast.next.next;slow = slow.next;if(slow == fast){return true;}}return false;}
}
BM7 链表中环的入口结点
解题思路

在这里插入图片描述

还有借助双指针slow和fast,之后要寻找规律
假设双指针在结点C相遇,且slow是第一次走到C,A->B的距离为X,B->C的距离为Y
则slow走了X+Y,fast每次走的是slow的两倍,所以fast走了2*(X+Y)
fast走的2*(X+Y)实际路径是A->B B->C C->B B->C,我们不知道的是C->B的距离,根据上述条件,可以知道
C->B的距离= 2*(X+Y)-(A->B)-(B->C) -(B->C)= 2*(X+Y)-X-Y-Y=X
噢,原理规律就是,相遇点C->B(环入口)的距离,竟然等于从头结点到环入口的距离
那好办了,slow还是在C开始走,fast回到头结点,和slow一起一步一步走,走到他俩遇见的结点,就是环的入口结点。破案。
import java.util.*;
public class Solution {public ListNode EntryNodeOfLoop(ListNode pHead) {//双指针 空间O(1) 时间O(N)if(pHead == null || pHead.next == null){return null;}ListNode fast = pHead;ListNode slow = pHead;while(fast != null && fast.next != null){fast = fast.next.next;slow = slow.next;//有环,双指针会在环中相遇if(slow == fast){break;}}if(fast == null || slow == null){return null;}fast = pHead;//与第一次相遇的节点相同速度出发,相遇节点为入口结点while(fast != slow){fast = fast.next;slow = slow.next;}return fast;}
}
还有一种办法是,不断的遍历链表,借助集合,存储遍历到的结点;
每遍历一个结点判断当前集合中是否已经有这个结点,有的话直接return。
    public ListNode EntryNodeOfLoop(ListNode pHead) {//hash 空间O(N) 时间O(N)HashSet<ListNode> set = new HashSet<>();while(pHead != null){if(set.contains(pHead)){return pHead;}set.add(pHead);pHead = pHead.next;}return null;}
BM8 链表中倒数最后k个结点
解题思路
两次循环,先统计长度,之后遍历到count-k处,return
 public ListNode FindKthToTail (ListNode pHead, int k) {// 最简单的想法,但是需要两次遍历//先遍历,看链表长度,然后遍历count-k次,returnListNode dummy = pHead;if(pHead == null){return pHead;}int count = 1;while(dummy.next != null){count++;dummy = dummy.next;}if(count < k){return null;}dummy = pHead;while(count > k){dummy = dummy.next;count --;}return dummy;}
双指针
fast先走k步
之后fast和slow一起走,当fast走到链表尾部时,slow所在的结点刚好是倒数第k个
public class Solution {public ListNode FindKthToTail (ListNode pHead, int k) {//快慢指针if(pHead == null){return pHead;}ListNode fast = pHead;ListNode slow = pHead;while(k-- > 0){if(fast != null){fast = fast.next;}else{return null;}}while(fast != null){fast = fast.next;slow = slow.next;}return slow;}
}
BM9 删除链表的倒数第n个节点
解题思路
双指针
注意,有可能删除第1个结点,所以定义一个虚拟头结点res
fast从res开始,先走n步
实际上就是从head开始走了n-1步
当fast走到链表尾部时,slow就走到了倒数第n-1个结点,跳过第n个结点即可:slow.next = slow.next.next
import java.util.*;
public class Solution {public ListNode removeNthFromEnd (ListNode head, int n) {// 双指针//注意有可能删除第一个,所以使用一个头节点if(head == null){return head;}ListNode res = new ListNode(-1);res.next = head;ListNode slow = res;ListNode fast = res;//fast先走n步for(int i=0;i<n;i++){fast = fast.next;}while(fast.next != null){fast = fast.next;slow = slow.next;   }slow.next = slow.next.next;return res.next;}
}
BM10 两个链表的第一个公共结点
解题思路
第一种方法是先遍历两个链表的长度len1和len2;
如果len1>len2, 链表1先走len1-len2步,因为公共部分在尾部,要尾部对齐;
之后同时遍历链表1和链表2,如果遇到两者相等,直接return(有公共结点会返回,没有会一起走到尾部,返回null)
代码较为繁琐,也可能是我太菜了,不会优化
 public ListNode FindFirstCommonNode(ListNode pHead1, ListNode pHead2) {//1.先统计两个链表的长度len1,len2ListNode dummy1 = pHead1;ListNode dummy2 = pHead2;int len1 = 0;while(dummy1 != null){dummy1 = dummy1.next;len1++;}int len2 = 0;while(dummy2 != null){dummy2 = dummy2.next;len2++;}//2,较长的链表,指针先走|len1-len2|,因为链表的公共部分在尾部,尾部对齐dummy1 = pHead1;dummy2 = pHead2;if(len1 > len2){while(len1 - len2 > 0){dummy1 = dummy1.next;len1--;}}if(len1 < len2){while(len2 - len1 > 0){dummy2 = dummy2.next;len2--;}}//3.两个链表同时移动,如果遇到节点相同,return,如果有一方已经=null,直接return nullwhile(dummy1 != null && dummy2 != null){if(dummy1 == dummy2){return dummy1;}else{dummy1 = dummy1.next;dummy2 = dummy2.next;}}return null;}
第二种方法,还是双指针,找规律
链表1的长度为len1,链表2的长度为len2,
指针n1和指针n2,一个从链表1出发,一个从链表2出发,两者都走len1+len2个长度
如果有公共结点,如样例{1,2,3}{4,5}{6,7}
/n1走:1,2,3,6,7,null,4,5,6
n2走:4,5,6,7,null,1,2,3,6
走到相等的时候就是公共起始点
没有公共节点如{1}{2,3},{},n1:1,2,3,null  n2:2,3,1,null 走到最后相等都为空
public class Solution {public ListNode FindFirstCommonNode(ListNode pHead1, ListNode pHead2) {ListNode n1 = pHead1;ListNode n2 = pHead2;while(n1 != n2){n1 = (n1 == null)? pHead2 : n1.next;//n1第一次走到空的时候是phead1遍历完n2 = (n2 == null)? pHead1 : n2.next;}return n1;}
}
BM11链表相加(二)
解题思路
先把两个链表进行翻转,这样就可以按位加
每个链表结点存储的值在0-9,所以如果计算出来超过9,需要借助变量isTen记录超过9的十位数是多少
链表结点的值取当前位置两个值相加+isTen之后的个位数
import java.util.*;
public class Solution {public ListNode addInList (ListNode head1, ListNode head2) {// write code herehead1 = reverse(head1);head2 = reverse(head2); ListNode ans = new ListNode(-1);ListNode dummy = ans;int isTen = 0;int val=0;while(!(head1 == null && head2 == null)){val = isTen;if(head1 != null){val += head1.val;head1 = head1.next;}if(head2 != null){val += head2.val;head2 = head2.next;}isTen = val/10;dummy.next = new ListNode(val%10);dummy = dummy.next;}if(isTen > 0){dummy.next = new ListNode(isTen);}return reverse(ans.next);}public ListNode reverse(ListNode head){if(head == null){return head;}ListNode cur = head;ListNode per = null;while(cur!= null){ListNode tmp = cur.next;cur.next = per;per = cur;cur = tmp;}return per;}
}
BM12 单链表排序
解题思路
借助数组,存储当前链表的所有结点值
对数组进行排序
重新建立链表返回
public class Solution {public ListNode sortInList (ListNode head) {// 借助数组ListNode dummy = head;List<Integer> list = new ArrayList<>();while(dummy != null){list.add(dummy.val);dummy = dummy.next;}Collections.sort(list);dummy = head;for(int i=0;i<list.size();++i){dummy.val = list.get(i);dummy = dummy.next;}return head;}
}
BM13 判断一个链表是否为回文结构
解题思路
借助栈,先将链表的节点值依次入栈
之后,从头遍历链表,将其值与栈顶元素相比,如果相等则继续遍历,栈顶元素出栈;否则直接return false
    public boolean isPail (ListNode head) {// write code here//借助一个栈,空间复杂度O(N),时间复杂度O(N)Stack<Integer> stack = new Stack();if(head == null){return true;}ListNode dummy = head;while(dummy != null){stack.push(dummy.val);dummy = dummy.next;}dummy = head;while(!stack.isEmpty()){if(stack.pop() != dummy.val){return false;}dummy  = dummy.next;}return true;}
方法二,快慢指针
slow每次走一步,fast每次走两步
fast走到链表末尾时,slow走到链表中间
将slow到fast的子链表进行翻转,翻转后的第一个结点由slow指向
之后fast从原始链表头结点开始遍历,判断slow与fast是否相等
public class Solution {public boolean isPail (ListNode head) {// write code here//双指针,slow往后一步,fast走两步,当fast走到末尾时,slow走到中间//后半段进行反转//时间复杂度O(N) 空间复杂度O(1)if (head == null || head.next == null) {return true;}ListNode slow = head;ListNode fast = head;while (fast != null && fast.next != null) {fast = fast.next.next;slow = slow.next;}slow = reverse(slow);fast = head;while (slow != null && fast != null) {if (slow.val != fast.val) {return false;}slow = slow.next;fast = fast.next;}return true;}public ListNode reverse(ListNode head) {ListNode per = null;ListNode cur = head;while (cur != null) {ListNode tmp = cur.next;cur.next = per;per = cur;cur = tmp;}return per;}
}

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ThemeForest – Canvas 7.2.0 – 多用途 HTML5 模板

ThemeForest 上的 HTML 网站模板受到全球数百万客户的喜爱。与包含网站所有页面并允许您在 WP 仪表板中自定义字体和样式的 WordPress 主题不同&#xff0c;这些设计模板是用 HTML 构建的。您可以在 HTML 编辑器中编辑模板&#xff0c;但不能在 WordPress 上编辑模板&#xff0…

医疗器械标准目录汇编2022版共178页(文中附下载链接!)

为便于更好地应用医疗器械标准&#xff0c;国家药监局医疗器械标准管理中心组织对现行1851项医疗器械国家和行业标准按技术领域&#xff0c;编排形成《医疗器械标准目录汇编&#xff08;2022版&#xff09;》 该目录汇编分为通用技术领域和专业技术领域两大类&#xff0c;通用…

ChatGPT付费创作系统V2.3.4独立版 +WEB端+ H5端 + 小程序最新前端

人类小徐提供的GPT付费体验系统最新版系统是一款基于ThinkPHP框架开发的AI问答小程序&#xff0c;是基于国外很火的ChatGPT进行开发的Ai智能问答小程序。当前全民热议ChatGPT&#xff0c;流量超级大&#xff0c;引流不要太简单&#xff01;一键下单即可拥有自己的GPT&#xff0…

14链表-环形链表、龟兔赛跑算法

目录 LeetCode之路——141. 环形链表 分析&#xff1a; 解法一&#xff1a;哈希表 解法二&#xff1a;龟兔赛跑 LeetCode之路——141. 环形链表 给你一个链表的头节点 head &#xff0c;判断链表中是否有环。 如果链表中有某个节点&#xff0c;可以通过连续跟踪 next 指针…

优化方法的应用(optimtool.example)

import optimtool as oo from optimtool.base import np, sp, pltpip install optimtool>2.4.2优化方法的应用&#xff08;optimtool.example&#xff09; import optimtool.example as oeLasso问题&#xff08;Lasso&#xff09; oe.Lasso.[函数名]([矩阵A], [矩阵b], [因…

矩阵的c++实现(2)

上一次我们了解了矩阵的运算和如何使用矩阵解决斐波那契数列&#xff0c;这一次我们多看看例题&#xff0c;了解什么情况下用矩阵比较合适。 先看例题 1.洛谷P1939 【模板】矩阵加速&#xff08;数列&#xff09; 模板题应该很简单。 补&#xff1a;1<n<10^9 10^9肯定…

QGIS文章四——对遥感影像进行土地类型分类

关于土地类型分类&#xff0c;按照性质、用途、利用现状有不同的分类标准。 一、按照国家土地性质分类标准&#xff0c;一般分五类:商业用地、综合用地、住宅用地、工业用地和其他用地。 二、按照用途进行土地分类&#xff1a;可以分为农用地、建设用地和未利用土地&#xff0c…

专题一:双指针【优选算法】

双指针应用场景&#xff1a; 数组划分、数组分块 目录 一、移动0 二、复写0 从后向前 三、快乐数 链表带环 四、盛水最多的容器 单调性双指针 五、有效三角形个数 单调性双指针 六、和为s的两个数字 七、三数之和 细节多 需再练 一、移动0 class Solution { public:void move…

【iptables 实战】9 docker网络原理分析

在开始本章阅读之前&#xff0c;需要提前了解以下的知识 阅读本节需要一些docker的基础知识&#xff0c;最好是在linux上安装好docker环境。提前掌握iptables的基础知识&#xff0c;前文参考【iptables 实战】 一、docker网络模型 docker网络模型如下图所示 说明&#xff1…

如何禁用Windows 10快速启动(以及为什么要这样做)

如果您不想启用Windows 10快速启动&#xff0c;则可以相对轻松地禁用它。 快速启动是一项功能&#xff0c;首先在 Windows 8 中作为快速启动实现&#xff0c;并延续到 Windows 10&#xff0c;让您的 PC 更快地启动&#xff0c;因此得名。虽然这个方便的功能可以通过将操作系统…

MySQL 事务隔离级别与锁机制详解

目录 一、前言二、事务及其ACID属性三、并发事务处理带来的问题四、事务隔离级别4.1、隔离级别分类4.2、查看当前数据库的事务隔离级别:4.3、临时修改数据库隔离级别&#xff08;重启MySQL后恢复到配置中的级别&#xff09; 五、表数据准备六、MySQL常见锁介绍5.1、锁分类5.2、…

软考高级之系统架构师之设计模式

概述 设计模式是一种通用的设计方法&#xff0c;实际开发中可能不止23种。为方便理解和应用&#xff0c;一般分为3类&#xff1a; 创建型&#xff0c;通过采用抽象类所定义的接口&#xff0c;封装系统中对象如何创建、组合等信息。工厂方法模式、抽象工厂模式、单例模式、建造…

PsychoPy Coder 心理学实验 斯特鲁普效应

选题&#xff1a;斯特鲁普效应实验 选题来源&#xff1a;你知道的「有趣的心理学实验」有哪些&#xff1f; - 知乎 (zhihu.com) 测试目标&#xff1a;探索斯特鲁普效应&#xff0c;即被试在判断文字颜色时&#xff0c;当文字的颜色与其所表示的颜色名称不一致时&#xff0c;是…

0基础学习VR全景平台篇 第103篇:使用英文、法文、德文等其他语言

大家好&#xff0c;欢迎观看蛙色VR官方系列——后台使用课程&#xff01; 蛙色VR平台目前已支持中英文语言进行切换&#xff0c;本期教程为大家带来&#xff0c;如何实现日文、法文、德文、俄文乃至其他小语种离线包里语言切换教程&#xff01; 语言切换样例展示 一、使用本功…

高级SQL语句

高级SQL语句&#xff08;进阶查询&#xff09; 先准备2个表 &#xff0c;一个location表&#xff1a; use market; create table location(Region char(20),Store_Name char(20)); insert into location values(East,Boston); insert into location values(East,New Yor…

【树】树的直径和重心

目录 一.树的直径 &#xff08;1&#xff09;定义 &#xff08;2&#xff09;思路 &#xff08;3&#xff09;例题 &#xff08;4&#xff09;std(第一小问) 二.树的重心 &#xff08;1&#xff09;介绍 &#xff08;2&#xff09;求重心 &#xff08;3&#xff09;例…

一文教你搞懂Redis集群

一、Redis主从 1.1、搭建主从架构 单节点的Redis的并发能力是有上限的&#xff0c;要进一步的提高Redis的并发能力&#xff0c;据需要大家主从集群&#xff0c;实现读写分离。 共包含三个实例&#xff0c;由于资源有限&#xff0c;所以在一台虚拟机上&#xff0c;开启多个red…

小程序入门笔记(一) 黑马程序员前端微信小程序开发教程

微信小程序基本介绍 小程序和普通网页有以下几点区别&#xff1a; 运行环境&#xff1a;小程序可以在手机的操作系统上直接运行&#xff0c;如微信、支付宝等&#xff1b;而普通网页需要在浏览器中打开才能运行。 开发技术&#xff1a;小程序采用前端技术进行开发&#xff0c;…

Sentinel安装

Sentinel 微服务保护的技术有很多&#xff0c;但在目前国内使用较多的还是Sentinel&#xff0c;所以接下来我们学习Sentinel的使用。 1.介绍和安装 Sentinel是阿里巴巴开源的一款服务保护框架&#xff0c;目前已经加入SpringCloudAlibaba中。官方网站&#xff1a; 首页 | Se…

Curve 文件存储的缓存策略

Curve 文件存储简介 Curve 文件存储的架构如下&#xff1a; 客户端 Posix 兼容&#xff1a;像本地文件系统一样使用&#xff0c;业务无缝接入&#xff0c;无侵入性&#xff1b; 独立的元数据集群&#xff1a;元数据分布式设计&#xff0c;可以无限扩展。同一文件系统可以在数…