这里的每一个题大家都要仔细完成,这些题目每个我都至少思考了两个小时左右(沉重心,慢慢来)
1.反向链表的实现(对链表进行翻转)(力扣有)
(1)图示
(2)思路
遍历整个数组不断的进行头插法就可以从正向变为反向数组
(3)代码实现
前面两个指的是链表为空和只有一个元素的情况
有一个细节就是display的方法永远从头结点开始,头节点改变了也一样
如果想从指定位置打印可以传入参数然后让头结点等于参数就可以在指定位置往后进行打印了
2.找出链表的中间节点
. - 力扣(LeetCode)
给你单链表的头结点 head
,请你找出并返回链表的中间结点。
如果有两个中间结点,则返回第二个中间结点。
(1)第一种方法就是遍历整个链表然后定义一个计数器,每次遍历一个节点就计数器加一,之后计数器的值除2就可以了(太过简单不建议面试的时候使用这种方法太简单)
(2)第二种方法是定义3个节点,其中个节点分别为cur slow fast这三个节点的初始都是标记头节点的。然后fast节点和slow节点分别遍历整个节点,遍历到最后slow代表的节点就是中间节点,不相信可以自己带入我上面画出的节点进行遍历验证。
(3)第二种的方法实现
我们要注意的一点就是,while中的循环条件&&的左右不能替换,因为一但替换的化会发生空指针异常,万一一开始就是空的节点,然后它指向下一个就会发生异常
3.输入一个链表然后输出它的倒数第k个节点(力扣上面搜)
遍历整个链表,然后定义计数器来判断有多少个节点 ,定义三个节点分别为cur slow fast ,其中fast先走k-1步,然后slow和fast一起走到fast走到空为止,这时候slow走到的位置就是倒数第k个位置,大家可以带入链表实验一下
先搞一个大致的框架然后再对框架的细节进行弥补
万一没走完k-1步那么就会发生空指针异常所以为了防止这种情况的发生我们需要对k进行判断
再while中进行判断k的值在每次循环之后是否都是合法的
4.将两个有序链表合并成一个有序链表(力扣上面进行搜索)
图示
先定义一个虚拟节点,然后节点进行串联,然后每当下一个就和另外一个节点进行比较来继续穿,最后返回头结点就可以遍历整个链表搞好排序了
5.以给定值x为基准将链表分割成两部分,所有小于x的结点排在大于或等于x的结点之前 。(力扣上面搜)
给一个x,x的值等于30,那么链表的左边是比30小右边比30要大,
题目稍微修改一下
现有一链表的头指针ListNode*pHead,给一定值x,编写一段代码将小于x的节点排在其余节点之前,且不能改变原来数据的顺序,返回重新排序后的链表的头指针。
(1)定义两个不同的分别为bs 和be这两个是指的比x小的数字,第二个是as和ae这两个是指比x大的数字,到后面直接把这两个链表给结合一下就可以了,然后要保证顺序没有变化就需要进行尾插法,最后返回新的节点的头节点就行了
(2)先定义一个cur然后遍历整个链表,小于放入bs中,大于放入as中,(用)
第一次插入的时候bs和be(同理)是指向同一个的,然后再放入一个就变成be了,接下来插入的节点就全部插入be的后面了(as ae同理),最后让be的next等于as就可以了,
代码实现(总代码)
public ListNode partition(int x) {// write code here//定义一个cur 指向链表的头节点ListNode cur = head;ListNode bs = null;ListNode be = null;ListNode as = null;ListNode ae = null;//使用cur来遍历 所有的节点while (cur != null) {if(cur.val < x) {if(bs == null) {bs = cur;be = cur;}else {be.next = cur;be = be.next;}}else {// >= xif(as == null) {as = cur;ae = cur;}else {ae.next = cur;ae = ae.next;}}cur = cur.next;}if(bs == null) {return as;}be.next = as;if(as != null) {ae.next = null;}return bs;}
如果没有小于x的就会发生空指针异常,所以如果bs不等于空那么就让be.next =as 然后返回bs
这样虽然解决了一个段有一个段没有的问题,但是还有一种情况就是,不知道什么时候结束
大家再遍历一个链表结束的时候是next的值为null的时候结束
但是这段代码结束的时候ae没有为空,那么客户端就会不知道啥时候结束,所以as如果as不等于空那么ae的next就是null的我们手动把ae的next清空并不会影响排序和34这个值。
6.链表的回文结构 链表的回文结构_牛客题霸_牛客网1:00:00
回文可以理解为链表的结构是对称的,也就是数据是对称的,12,23,23,12这就是一个回文结构还有12,23,24,23,12
所以先定义两个指针来标记链表的尾部和头部
找到中间节点,先定义一个fast再定义一个slow,fast走两步slow走一步,fast走到null的时候结束循环
把中间节点后面给反转过来如果相同就是回文节点
奇数
(1)将后面一段进行反转
中间节点为slow slow的下一个节点为cur fast节点为curNext
slow往后面走,cur等于slow ,curNext往后面走发现为空了这时候cur等于slow这时候就将这个链表给反转完成了,这时候cur再往后面走走到空 fast和slow一个位置
(2)fast不走
(3)这时候两边同时往中间走然后判断相同不相同直接return false
偶数情况差不多
(1)奇数的话slow和fast不会相遇
代码实现
public boolean chkPalindrome() {// write code hereif(head == null) {return true;}//1. 找中间节点ListNode fast = head;ListNode slow = head;while (fast != null && fast.next != null) {fast = fast.next.next;slow = slow.next;}//2.翻转ListNode cur = slow.next;while (cur != null) {ListNode curNext = cur.next;cur.next = slow;slow = cur;cur = curNext;}//3.一个往前 一个往后while (slow != head) {if(slow.val != head.val) {return false;}//偶数情况if(head.next == slow) {return true;}head = head.next;slow = slow.next;}return true;}public boolean hasCycle() {ListNode fast = head;ListNode slow = head;while(fast != null && fast.next != null) {fast = fast.next.next;slow = slow.next;if(fast == slow) {return true;}}return false;}
7.给你两个链表看你的两个链表是不是相交的?力扣上面自己搜
是一个y字形状
这样就相交了(相交的交点的地址是一样的)
下图两种情况都是可以的
headA 和headB同?时走如果相遇了就是我们相交的交点,其中有一个问题?谁规定的在这这两个岔开的两个链表的节点数字是一样的,你不知道节点数有啥办法解决?
首先我们要知道的一点就是,这两个节点再相交点之后的节点是一样的所以,我们只需要将两个节点相减就可以发现哪个节点比哪个节点大!
所以
(1)求长度
(2)走插值步,相遇之后就是相交的点节点
代码实现
(1)两个链表为空要进行判断
(2)定义pl永远指向最长的链表 ps指向最短的链表
(3)len用来记录差值
(4)如果差值为复数那么pl和ps交换位置再用len记录
(5)这样就能包装p1指向最长ps指向最短,len一定时正数
(6)循环不解释了自己看自己解读(第一个循环包装p1和ps走向相遇节点的旅程时一样的,之后,一人一步走)
(7)第二个循环一人一步走
(8)最后return一个pl就可以了
(9)其中有一个漏洞就是:如果节点为空的话也时可以通过的因为空也是相同的,所以我们要对都是null的进行判断
大(0)是m+n = n
(10)下面代码是官方的解答
8.判断链表是非有环(最后一个节点和第一个节点或者其他节点来进行连接)
链表是跳着走的
一圈以后他们就相遇了
(1)对于一步两步的情况,我们可以发现,他们的距离差(也就是环的周长)是一个定值,而且这个定值是2的倍数。一个人每次走一步,另一个人每次走两步,就相当于他们以相同的方向在环上移动,且速度不同。这样当他们相遇时,他们的距离差必须是2的倍数,所以他们必须在某个点相遇。
(2)但是对于两步三步的情况,他们的距离差并不是一个定值。一个人每次走两步,另一个人每次走三步,就相当于他们以相同的方向在环上移动,但速度不同。如果他们的速度比较相似,那么他们有可能在某个点相遇,但如果速度相差太大,他们就很难相遇。因为他们在相差太大的情况下,它们将不再以相同的方向移动。有时他们之间的差距会变得比开始时更大,有时会变得更小,但总是无法保证他们是否会在某个点相遇。
所以,一个人每次走一步,另一个人每次走两步的情况是一种比较特殊的情况,而两步三步的情况却具有更大的不确定性。
证明: