代码随想录算法训练营第四天| 24. 两两交换链表中的节点 、 19.删除链表的倒数第N个节点 、面试题 02.07. 链表相交 、 142.环形链表II
想法:今天开始上难度了,哈哈,很有收获,温习了很多遗忘的知识点。
24. 两两交换链表中的节点link
题目描述:给你一个链表,两两交换其中相邻的节点,并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题(即,只能进行节点交换)。
想法:使用虚拟头节点,进行节点交换。
大致做法就是:先设置一个指针cur指向虚拟头节点,然后再设置三个指针f,s,t,分别指向cur.next
,cur.next.next
,cur.next.next.next
,然后进行移动操作。最后要注意:我们要返回的是虚拟头节点的next。
如下图所示:
// 设置虚拟头节点,便于操作
public ListNode swapPairs(ListNode head) {
if (head == null || head.next == null)
return head;
ListNode dummyNode = new ListNode(-1);
dummyNode.next = head;
ListNode cur = dummyNode;
// 分别是cur的next,next.next,next.next.next
// 用于交换节点的连接
ListNode first;
ListNode second;
ListNode third;
// cur != null 可以不加,因为cur.next != null表明了cur不为null
while (cur.next != null && cur.next.next != null) {
third = cur.next.next.next;
first = cur.next;
second = cur.next.next;
// 节点操作
cur.next = second;
second.next = first;
first.next = third;
// 关键点:移动cur,为下一次移动准备
cur = first;
}
return dummyNode.next;
}
}
19.删除链表的倒数第N个节点link
题目描述:给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。
做法:学习的代码随想录的做法,如下所示:
定义fast指针和slow指针,初始值为虚拟头结点,如图:
fast首先走n + 1步 ,为什么是n+1呢,因为只有这样同时移动的时候slow才能指向删除节点的上一个节点(方便做删除操作),如图:
fast和slow同时移动,直到fast指向末尾,如图:
删除slow指向的下一个节点,如图:
class Solution {
public ListNode removeNthFromEnd(ListNode head, int n) {
if(head==null)
return head;
//设置虚拟头节点
ListNode dummyNode=new ListNode(-1);
dummyNode.next=head;
//fast指针先走n+1步,然后fast和slow再一起走。
//直到fast为null,表示slow走到了倒数第n个节点的前面,然后进行删除操作
ListNode fast=dummyNode;
ListNode slow=dummyNode;
for(int i=0;i<=n;i++)
fast=fast.next;
while(fast!=null) {
fast=fast.next;
slow=slow.next;
}
slow.next=slow.next.next;
//返回时注意,dummyNode是虚拟节点,真正的节点是dummyNode.next
return dummyNode.next;
}
}
面试题 02.07. 链表相交link
题目描述:给你两个单链表的头节点 headA 和 headB ,请你找出并返回两个单链表相交的起始节点。如果两个链表没有交点,返回 null 。
想法:看着代码比较好理解,原理就是每次a或b指针交换指向的节点时就会抵消中间的差值,可以画个图感受一下;对于不相交时,两个会共同指向null值,返回null。
public class Solution {
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
if(headA==null || headB==null)
return null;
ListNode a=headA;
ListNode b=headB;
while(a!=b) {
//若a走到headA的尾部,然后就指向headB
//b同理
a=a==null?headB:a.next;
b=b==null?headA:b.next;
}
return a;
}
}
142.环形链表II link
题目:给定一个链表的头节点 head ,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。
别看代码长,其实比较好理解😂
思路:
// 先求出链表中环形链表节点的个数len(使用快慢指针,相遇的地方为环形链表内,然后让一个指针停下,另一个指针接着走,计算遇到停下指针的步数,即为len)
然后设置两个指针指向头节点,让其中一个先走len步,然后一起走,相遇的地方为入环的第一个节点。
public class Solution {
public ListNode detectCycle(ListNode head) {
if(head==null || head.next==head) {
return 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;
}
}
//注意:这里要判断一下,判断fast是避免环不存在
//为什么不是判断slow,因为fast=fast.next.next;可以导致fast为null,如果fast都没问题,那么slow也没问题
if(fast==null || fast.next==null)
return null;
//fast指针停止,slow指针移动,寻找环形节点的长度
int len=1;
while(true) {
slow=slow.next;
if(slow==fast) {
break;
}
len++;
}
ListNode a=head;
ListNode b=head;
//b先走len步
for(int i=0;i<len;i++) {
b=b.next;
}
while(true) {
if(a==b) {
return a;
}
a=a.next;
b=b.next;
}
}
}
希望对您有帮助,谢谢观看!