学习目标:
1.两两交换链表中的节点
2.删除链表的倒数第N个节点
3.面试题02.07.链表相交
4.142环形链表ll
5.总结
1.24两两交换链表中的节点
两两交换链表中相邻节点,需要设置虚拟头节点dummyhead,用这张图做类比,因为先让dummyhead指向2节点,再让2节点指向1节点,这时候需要将1节点和3节点用temp保存下来,因为当dummyhead指向2节点的时候1节点就丢失了,同理,当2节点指向1节点的时候3节点也丢失了,所以需要保存这两个位置上的节点。
代码如下:
class Solution {
public ListNode swapPairs(ListNode head) {
ListNode dummyhead = new ListNode(0,head);
ListNode cur = dummyhead;
while(cur.next!=null && cur.next.next!=null){
//两两交换
ListNode temp = cur.next;//保存第一个节点
ListNode temp1 = cur.next.next.next;//保存第二个节点后面一个
cur.next = cur.next.next;
cur.next.next = temp;
temp.next = temp1;
cur = cur.next.next;
}
return dummyhead.next;
}
}
2.19删除链表的倒数第N个节点
此题的技巧就是通过两个指针,当快指针指向n位置的时候,将快慢指针同时往后移,当块指针指向null的时候慢指针也就指向了倒数第n个数,但在这里要注意先让fast指针先走一步,因为删除操作必须要在删除节点的前一位进行操作。
class Solution {
public ListNode removeNthFromEnd(ListNode head, int n) {
ListNode dummyhead = new ListNode(0, head);
// 定义快慢指针,先让快指针n+1步,为了让慢指针指向要删除的前一位
ListNode fast = dummyhead;
ListNode slow = dummyhead;
n++;
while (n-- > 0) {
fast = fast.next;
}
while (fast != null) {
slow = slow.next;
fast = fast.next;
}
slow.next = slow.next.next;
return dummyhead.next;
}
}
3.面试题02.07.链表相交
这题主要思路是将两个链表的尾巴对齐,同时让两个指针从短的链表的头指针的位置一起向后遍历,也就是让指针所处位置相同。当两个指针的值一样的时候,则就是相交的点。
public class Solution {
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
ListNode a = headA;
ListNode b = headB;
int lenA=0,lenB=0;
while(a!=null){
a =a.next;
lenA++;
}
while(b!=null){
b =b.next;
lenB++;
}
a = headA;b=headB;
//方便计算,以A为长的一条
if(lenA < lenB){
//记录临时a长度
int tempLen = lenA;
lenA = lenB;
lenB = tempLen;
//记录临时a节点
ListNode tempNode = a;
a = b;
b = tempNode;
}
int len = lenA-lenB;
while(len-->0){
a = a.next;
}
while(a!=null){
if(a == b){
return a;
}
a= a.next;
b= b.next;
}
return null;
}
}
此题还有需要注意的点:a = headA;b=headB;这一段代码需要在交换a,b位置之前执行,因为在前面求链表长度的时候a,b节点已经移到了链表末尾,需要还原到头节点,当然创造两个新节点也可以但没必要。
4.142环形链表ll
这道题目涉及的数学知识比较多,需要画图解释。
首先定义了快慢指针,快指针以每次移动两个点的速度移动,慢指针则以一个点一次的速度移动,当它们可以相遇的时候一定有环,有人会问了,那有环的情况下慢指针会遇不上快指针吗,答案是不会,因为他们的相对速度是一次一个节点,所以一定会遇上。
所以就延申出了这么一张图,令x为起点到环入口的距离,y为环入口到相遇点的距离,z为相遇点到环出口的距离,因为肯定是在环中相遇的,快指针的速度又是慢指针的两倍,所以就有了以上的公式,2(x+y) = x+y + n(z+y),n是快指针转的圈数。 这时我们可以忽略转的圈数,因为最终的相对位置跟转的圈数无关,所以可以得到x = z的结论。
问题:为什么慢指针的公式是移动的距离是(x+y),而不是(x+y)+n(y+z)呢,因为在慢指针刚刚进入环的时的第一圈就能和慢指针遇上,可以看下面这张图:
当慢指针在刚进入入口的时候,假设快指针在后面,在慢指针到达下一个出口的时候,快指针一定已经超过了下一个出口,所以在此期间快慢指针一定会遇上。
所以,最后的结论是通过 x=z 来找到环的入口,使两个指针分别在起点和相遇点以相同的速度移动,最后相遇的点就是环的入口。
public class Solution {
public ListNode detectCycle(ListNode head) {
ListNode fast = head;
ListNode slow = head;
while (fast != null && fast.next != null) {
fast = fast.next.next;
slow = slow.next;
if (fast == slow) {
ListNode meetNode = fast;
ListNode beginNode = head;
while (meetNode != beginNode) {
meetNode = meetNode.next;
beginNode = beginNode.next;
}
return meetNode;
}
}
return null;
}
}
代码比较简单就不细琐了,主要是思路。