返回中间节点;返回倒数k节点;判断是否为环形链表(返回入环第一个节点)
Posted 小写丶H
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了返回中间节点;返回倒数k节点;判断是否为环形链表(返回入环第一个节点)相关的知识,希望对你有一定的参考价值。
今天我们使用典型的快慢指针解决这几个典型问题
一.返回中间节点
问题
给定一个头结点为 head 的非空单链表,返回链表的中间结点。(如果有两个中间结点,则返回第二个中间节点)
思路
这里我们设置两个指针,slow和fast,一个走一步,一个走两步,等fast走完链表,那么slow就在中间节点。
这里比较简单也好想,我就不画图了。一些小细节,我也在代码里解释到了。
代码
public ListNode middleNode(ListNode head) {
//定义快慢指针
ListNode fast=head;
ListNode slow=head;
//快指针遍历完的的标志
//这里fast!=null和fast.next!=null,这两个不能换位置哦,防止空指针异常。
//当fast为null时,就不会判断fast.next了。
while(fast!=null&&fast.next!=null){
//走两步
fast=fast.next.next;
//走一步
slow=slow.next;
}
return slow;
}
二.返回倒数k节点
问题
输入一个链表,输出该链表中倒数第k个结点。
(问题简洁,我们也好考虑)
思路
首先依然是两个指针,slow和fast,求倒数第k个,那么我们就让fast先走(k-1)步;因为返回的是slow,为什么是k-1步,也很好理解,不太理解的可以这样想。如果是求倒数第一个节点,那么slow和fast便应该处于同一个节点上。画图遍历一遍就可以理解了。
代码
public ListNode FindKthToTail(ListNode head,int k) {
//为空直接结束
if(head==null){
return null;
}
//求得倒数k不合法那也不行,k大的不合法在下面处理
if(k<=0){
return null;
}
//定义快慢指针
ListNode fast=head;
ListNode slow=head;
//让fast先走k-1步
while((k-1)!=0){
//这里就是在处理如果k大于链表的长度,那么依然返回null
if(fast.next!=null){
fast=fast.next;
k--;
}else{
return null;
}
}
//让slow和fast同时一块走动,当fast到尾部时,结束循环
while(fast.next!=null){
fast=fast.next;
slow=slow.next;
}
//返回slow
return slow;
}
三.判断是否有环形链表
问题
给定一个链表,判断链表中是否有环。
(如果链表中存在环,则返回 true 。 否则,返回 false 。)
环一定是存在尾部。
思路
定义一个快慢指针,slow和fast。slow走一步,fast走两步,当存在环的时候,slow和fast因为存在差距,所以在环中一定相遇。当slow==fast,那么就证明存在环;当fast.next ==null,那么证明没有环。
代码
public boolean hasCycle(ListNode head) {
//定义快慢指针
ListNode fast=head;
ListNode slow=head;
//fast走两步,slow走一步
while(fast!=null && fast.next!=null){
fast=fast.next.next;
slow=slow.next;
//相遇证明存在环
if(fast==slow){
break;
}
}
//证明没有环
if(fast==null || fast.next==null){
return false;
}
return true;
}
如果要返回其环的第一个节点
问题
给定一个链表,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。
思路
定义快慢指针,slow和fast,slow走一步,fast走两步,先找到slow和fast在环中的相遇位置;之后重置slow=head,然后继续走,但是这时,slow走一步,fast也走一步,当slow和fast相遇的时候,那么就是环入口的第一个节点。
代码
public ListNode detectCycle(ListNode head) {
//定义快慢指针
ListNode fast=head;
ListNode slow=head;
//fast走两步,slow走一步
while(fast!=null && fast.next!=null){
fast=fast.next.next;
slow=slow.next;
//相遇存在环
if(fast==slow){
break;
}
}
//确保存在环
if( fast == null || fast.next==null){
return null;
}
//让slow退回到head
slow=head;
//这时让slow和fast同时走一步,这个需要理解上面我画的图。
while(slow!=fast){
slow=slow.next;
fast=fast.next;
}
return slow;
}
以上是关于返回中间节点;返回倒数k节点;判断是否为环形链表(返回入环第一个节点)的主要内容,如果未能解决你的问题,请参考以下文章
链表经典面试题(反转链表,中间节点,倒数第k个节点,合并分割链表,删除重复节点)
链表题 剑指21.删除链表的倒数第n个节点剑指22.链表的倒数第k个节点234.回文链表141.环形链表142.环形链表Ⅱ 160.相交链表 21.合并两个有序链表