目录
Day 4 第二章 链表part02
- 今日任务
- 24.两两交换链表中的节点; 19.删除链表的倒数第N个节点; 面试题 02.07. 链表相交; 142.环形链表II; 总结
24. 两两交换链表中的节点
- 用虚拟头结点,这样会方便很多。
- 本题链表操作就比较复杂了,建议大家先看视频,视频里我讲解了注意事项,为什么需要temp保存临时节点。
- 题目链接:https://leetcode.cn/problems/swap-nodes-in-pairs/
- 视频讲解:https://www.bilibili.com/video/BV1YT411g7br
- 文章讲解:https://programmercarl.com/0024.%E4%B8%A4%E4%B8%A4%E4%BA%A4%E6%8D%A2%E9%93%BE%E8%A1%A8%E4%B8%AD%E7%9A%84%E8%8A%82%E7%82%B9.html
自己的思路(✅通过)
public static ListNode swapPairs(ListNode head) {
ListNode dummyHead = new ListNode();
dummyHead.next = head;
ListNode cur, pre, temp;
if(head == null || head.next == null) return head;
cur = head.next;
pre = head;
temp = dummyHead;
while(cur != null){
temp.next = cur;
pre.next = cur.next;
cur.next = pre;
temp = pre;
if(pre.next == null || pre.next.next == null) return dummyHead.next;
pre = pre.next;
cur = pre.next; //注意pre已经移到后面了,所以只需要一次next
}
return dummyHead.next;
}
❌ 错误点:java.lang.NullPointerException: Cannot read field "next" because "<parameter1>" is null
,通过判断当head
或head.next
为空时提前返回head
没有考虑输入的链表(头结点就取名为head吧)只有一个结点的情况,这个时候,如果访问她的next域就会报这个错误,解决方法是:在程序一开始就先对这种极端进行判断(一般需要直接返回head,注意:不能直接返回null,虽然head有可能为空,但是题目要求返回ListNode类型的数据,(如果head为null,访问 head不会报错))
递归版本
19.删除链表的倒数第N个节点
- 双指针的操作,要注意,删除第N个节点,那么我们当前遍历的指针一定要指向 第N个节点的前一个节点,建议先看视频。
- 题目链接:https://leetcode.cn/problems/remove-nth-node-from-end-of-list/
- 视频讲解:https://www.bilibili.com/video/BV1vW4y1U7Gf
- 文章讲解:https://programmercarl.com/0019.%E5%88%A0%E9%99%A4%E9%93%BE%E8%A1%A8%E7%9A%84%E5%80%92%E6%95%B0%E7%AC%ACN%E4%B8%AA%E8%8A%82%E7%82%B9.html
自己的思路(✅通过)
public static ListNode removeNthFromEnd(ListNode head, int n) {
ListNode cur, pre;
ListNode dummyHead = new ListNode();
dummyHead.next = head;
cur = head;
pre = dummyHead;
//cur向后移,使pre是cur做尾节点时的倒数第n+1个方便进行删除操作
//倒数第n个,cur需移n-1次
while(cur.next != null && n>1){
cur = cur.next;
n--;
}
//cur和pre一起向后移直到cur移到该链表的尾节点
while(cur.next != null){
cur = cur.next;
pre = pre.next;
}
pre.next = pre.next.next;
return dummyHead.next; //注意不是返回head,head可能被删了
}
面试题 02.07. 链表相交
- 本题没有视频讲解,大家注意 数值相同,不代表指针相同。
- 题目链接:https://leetcode.cn/problems/intersection-of-two-linked-lists-lcci/
- 文章讲解:https://programmercarl.com/%E9%9D%A2%E8%AF%95%E9%A2%9802.07.%E9%93%BE%E8%A1%A8%E7%9B%B8%E4%BA%A4.html
自己的思路(✅通过)
一开始把题目想错了,以为还有从头相交的情况,耽误了很多时间
▶️双指针思想:将A, B链表以尾部对齐,先把A链表的头节点移到与B的头节点平齐再遍历之后的节点看是否相交。
public static ListNode getIntersectionNode(ListNode headA, ListNode headB) {
ListNode curA = headA;
ListNode curB = headB;
//获取A,B链表的长度
int n1 = getSize(headA);
int n2 = getSize(headB);
int n;
//判断哪个链表更长,并移动长链表的节点
if(n1 > n2){
int x = n1 - n2;
while(x > 0){
curA = curA.next;
x --;
}
n = n2;
}else{
int x = n2 - n1;
while(x > 0){
curB = curB.next;
x --;
}
n = n1;
}
//遍历后面的节点
while(n > 0){
if(curA == curB){
return curA;
}
curA = curA.next;
curB = curB.next;
n --;
}
return null;
}
public static int getSize(ListNode head){
int size = 1;
ListNode temp = head;
while(temp.next != null){
temp = temp.next;
size ++;
}
return size;
}
142.环形链表II
- 算是链表比较有难度的题目,需要多花点时间理解 确定环和找环入口,建议先看视频。
- 题目链接:https://leetcode.cn/problems/linked-list-cycle-ii/
- 视频讲解:https://www.bilibili.com/video/BV1if4y1d7ob
- 文章讲解:https://programmercarl.com/0142.%E7%8E%AF%E5%BD%A2%E9%93%BE%E8%A1%A8II.html
双指针思路(看视频)
自己实在是没思路,决定直接看视频。
▶️双指针思想:快慢指针
a. 判断是否有环
- 大体思路: 定义一个快指针一个慢指针,如果有环快慢指针总会相遇,如果没环就不会相遇。
- 快满指针速度: 慢指针一次走一个节点,快指针每次走两个节点
b. 寻找环入口
public static ListNode detectCycle(ListNode head) {
ListNode fast = head, slow = head, cur = head;
while(fast != null && fast.next != null && fast.next.next != null){
fast = fast.next.next;
slow = slow.next;
if(fast == slow){
while(slow != cur){
slow = slow.next;
cur = cur.next;
}
return slow;
}
}
return null;
}
❌ 错误点:java.lang.NullPointerException: Cannot read field "next" because "<parameter1>" is null
,要想判断fast.next.next != null
前面必须提前判断fast != null && fast.next != null
链表总结
- 链表一定要分清节点和指针的概念。
new ListNode()
是真实存在的一个节点,head = new ListNode()
相当于 head指针指向了一个真实的节点,node = head
, 相当于node
和head
同时指向了这个真实的节点 - 尽量不要去动虚拟头节点,因为虚拟头节点本来就是个工具节点,操作后面的节点本身就好