代码随想录算法训练营day04 | 24. 两两交换链表中的节点 , 19.删除链表的倒数第N个节点 ,面试题 02.07. 链表相交 ,142.环形链表II
24. 两两交换链表中的节点
教程视频:https://www.bilibili.com/video/BV1YT411g7br/?vd_source=ddffd51aa532d23e6feac69924e20891添加链接描述
解法一
注意这里是交换链表节点,而不是交换链表节点中的值
public ListNode swapPairs(ListNode head) {
ListNode cur = new ListNode(0);
ListNode dummyHead = new ListNode(0);
dummyHead.next = head;
cur = dummyHead;
while(cur.next!=null && cur.next.next!=null){
ListNode tempNode = cur.next;
ListNode tempNode1 = cur.next.next.next;
cur.next = cur.next.next;
cur.next.next = tempNode;
tempNode.next = tempNode1;
cur = cur.next.next;
}
return dummyHead.next;
}
19.删除链表的倒数第N个节点
教程视频:
解法一:虚拟头节点+快慢指针
public ListNode removeNthFromEnd(ListNode head, int n) {
ListNode dumHead = new ListNode();
dumHead.next = head;
ListNode cur = dumHead;
ListNode slow = dumHead;
while(n!=0){
cur = cur.next;
n--;
}
while(cur.next!=null){
slow = slow.next;
cur = cur.next;
}
//此时 dumHead 为倒数n+1个结点
slow.next = slow.next.next;
return dumHead.next;
}
面试题 02.07. 链表相交
教程视频:
解法一:链表右对齐
这题要抓住相交后节点后的链表长度一致,因此要先将两链表后对齐,之后再进行比对.
同时,本题不需要修改链表元素,所以不使用虚拟头节点.
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
// 求两链表的长度
ListNode curA = headA;
int lenA = 0;
while(curA!=null){
lenA++;
curA = curA.next;
}
ListNode curB = headB;
int lenB = 0;
while(curB!=null){
lenB++;
curB = curB.next;
}
curA = headA;
curB = headB;
//让链表B为长链表的头,lenB是其长度
if(lenA>lenB){
ListNode temp = curA;
curA = curB;
curB = temp;
int tempLen = lenA;
lenA = lenB;
lenB = tempLen;
}
//求节点数差值
int gap = lenB - lenA;
while(gap!=0){
curB = curB.next;
gap--;
}
//此时,从 curA curB开始的节点数值相等
while(curA!=null){
if(curA == curB){
return curA;
}
curA = curA.next;
curB = curB.next;
}
return curA;
}
142.环形链表II
教程视频:
解法一:环形链表操作(快慢指针判断环+找环入口)
环形链表主要考察两个点:
1.如何判断环形存在
- 注意环形链表不能遍历,否则会陷入死循环.
- 判断环存在要使用快慢指针,分别定义 fast 和 slow 指针,从头结点出发,fast指针每次移动两个节点,slow指针每次移动一个节点,如果 fast 和 slow指针在途中相遇,说明这个链表有环。
2.如何寻找环入口
确定有环时,快慢指针在环中相遇.
经推理可知:x = (n - 1) (y + z) + z
( 详细推理过程见:https://programmercarl.com/0142.%E7%8E%AF%E5%BD%A2%E9%93%BE%E8%A1%A8II.html )
上式说明, 从相遇点和头节点以相同速度移动,相遇的地方就是环形入口的节点。
public ListNode detectCycle(ListNode head) {
//定义快慢指针
ListNode fast = new ListNode();
ListNode slow = new ListNode();
fast.next = head;
slow.next = head;
//判断是否有环
while(fast!=null && fast.next!=null){
fast = fast.next.next;
slow = slow.next;
if(fast==slow){
//记录相遇的位置
ListNode index2 = fast;
ListNode index1 = new ListNode();
index1.next = head;
//寻找环入口
while(index1!=index2){
index1 = index1.next;
index2 = index2.next;
}
return index1;
}
}
//没环则输出null
return null;
}
总结
1.使用虚拟头节点时,返回节点使用虚拟头节点表示,而不使用题干给出的head表示;
2.与链表倒数n元素相关的题可用快慢指针处理;
3.相交元素要抓住相交后链表长度一致;
4.环形链表不能遍历,需要用快慢指针来确定环存在以及寻找环入口.