1.LeetCode24. 两两交换链表中的节点
题目链接:https://leetcode.cn/problems/swap-nodes-in-pairs/description/
文章链接: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
视频链接:https://www.bilibili.com/video/BV1YT411g7br
思路:
本题的关键有两点:
①转移顺序
图片来自代码随想录
②返回的是虚拟头结点的next节点,即:dump.next
虚拟头结点始终指向head节点。
解释如下:
在第一次循环中,虚拟头结点被cur指针引用,cur.next=second,就将虚拟头结点的next指向了second,这样虚拟头结点指向了新的头结点。而第一次循环后,cur=first,即cur指向了新的一个节点first,cur也就不会对虚拟头结点进行操作了。
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
class Solution {
public ListNode swapPairs(ListNode head) {
ListNode dump = new ListNode(0);//虚拟头结点
dump.next=head;
ListNode cur=dump;
ListNode first;
ListNode second;
ListNode temp;
while(cur.next!=null&&cur.next.next!=null){
temp=cur.next.next.next;
first=cur.next;
second=cur.next.next;
cur.next=second;
second.next=first;
first.next=temp;
cur=first;
}
return dump.next;
}
}
2.LeetCode19.删除链表的倒数第N个节点
题目链接:https://leetcode.cn/problems/remove-nth-node-from-end-of-list/description/
文章链接: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
视频链接:https://www.bilibili.com/video/BV1vW4y1U7Gf
思路:
使用快慢指针的方式。fast快指针和slow慢指针,两者保证一定的间隔,然后整体移动,当fast等于null时,slow恰好处在需要处理的节点位置。这里的重点是要确定处理哪个节点,以及间隔应该是多少合适。
①因为是删除节点,我们需要获取到待删除节点的前驱节点,也就是slow最终要指向的节点;
②为了保证最终slow能指向待删除节点的前驱节点,fast和slow之间要间隔n个节点。这样,当fast等于null时,slow处在倒数第n+1个节点,即倒数第n个节点的前驱节点处。
解法:
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
class Solution {
// public ListNode removeNthFromEnd(ListNode head, int n) {
// int size=0;
// ListNode cur=head;
// while(cur!=null){
// size++;
// cur=cur.next;
// }
// int index=size-n;
// if(index<0||index>=size) return null;
// ListNode dump=new ListNode(0);//虚拟头结点
// dump.next=head;
// ListNode pre=dump;
// for(int i=0;i< index;i++){
// pre=pre.next;
// }
// pre.next=pre.next.next;
// return dump.next;
// }
//双指针
public ListNode removeNthFromEnd(ListNode head, int n) {
ListNode dump = new ListNode(0);
dump.next=head;
ListNode fast=dump;
ListNode slow=dump;
while(n--!=0&&fast!=null){
fast=fast.next;
}
fast=fast.next;//为了保证在fast和slow两个指针整体移动时,当fast等于null时,slow能够指向删除节点的前一个节点
while(fast!=null){
fast=fast.next;
slow=slow.next;
}
slow.next=slow.next.next;
return dump.next;
}
}
代码分析:
重点是如何要确定fast的起始位置,以保证与slow之间间隔n个节点。代码如下:
ListNode fast=dump;
ListNode slow=dump;
while(n--!=0&&fast!=null){
fast=fast.next;
}
fast=fast.next;//为了保证在fast和slow两个指针整体移动时,当fast等于null时,slow能够指向删除节点的前一个节点
3.面试题 02.07. 链表相交
题目链接:https://leetcode.cn/problems/intersection-of-two-linked-lists-lcci/description/
文章链接: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
思路:
解题的关键是要抹除两个链表之间的长度差。有两种方式解答:
①方式1. 获取两个链表的长度,并计算两个链表长度差,然后让长链表的头结点的指针往前移动长度差个节点,使得两个链表的起始指针位于同一起跑线上,之后两个指针同时往前移动,比较节点是否相同;
②方式2. 使用双指针形式。两个指针A和B分别在两个链表上同时移动,A指向短链表,B指向长链表,当短链表的A指针为null时,其指向长链表的头结点,此时B指针移动了两个链表相同长度的那部分距离,剩下的就是长度差值;此时A和B都在长链表上,当A和B继续同时移动时,两者移动的距离就是两个链表的长度差。当B为null时,其指向短链表的头节点,此时A在长链表上移动了长度差,剩下的长度是两个链表相同长度的那部分距离,即此时长短链表长度差被抹除,A和B处在同一起跑线上。
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) {
* val = x;
* next = null;
* }
* }
*/
public class Solution {
// public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
// int sizeA=0;
// int sizeB=0;
// ListNode curA=headA;
// ListNode curB=headB;
// while(curA!=null){
// sizeA++;
// curA=curA.next;
// }
// while(curB!=null){
// sizeB++;
// curB=curB.next;
// }
// ListNode startA=headA;
// ListNode startB=headB;
// int n=sizeA-sizeB;
// if(n>=0){
// while(n--!=0){
// startA=startA.next;
// }
// }else{
// while(n++!=0){
// startB=startB.next;
// }
// }
// while(startA!=null&&startB!=null&&startA!=startB){
// startA=startA.next;
// startB=startB.next;
// }
// return startA;
// }
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
ListNode p1=headA;
ListNode p2=headB;
while(p1!=p2){
if(p1==null){
p1=headB;
}else{
p1=p1.next;
}
if(p2==null){
p2=headA;
}else{
p2=p2.next;
}
}
return p1;
}
}
代码解析:
链表相交,是两个节点相同,不是值相同
4.LeetCode 142.环形链表II
题目链接:https://leetcode.cn/problems/linked-list-cycle-ii/description/
文章链接:https://programmercarl.com/0142.%E7%8E%AF%E5%BD%A2%E9%93%BE%E8%A1%A8II.html
视频链接:https://www.bilibili.com/video/BV1if4y1d7ob
思路:
解题关键为:确定相遇点,由相遇点出发确定入口点。
①使用快慢指针找到相遇点,其中快指针fast每次移动两个节点,慢指针slow每次移动一个节点,节点相同处为相遇点;
②找到相遇点后,定义两个指针,一个指针从头结点出发,一个指针从相遇点出发,每次移动一个节点,节点相同处为环入口。
解法:
/**
* Definition for singly-linked list.
* class ListNode {
* int val;
* ListNode next;
* ListNode(int x) {
* val = x;
* next = null;
* }
* }
*/
public class Solution {
public ListNode detectCycle(ListNode head) {
ListNode fast=head;
ListNode slow=head;
while(fast!=null&&fast.next!=null){//若为null,说明没有环;否则有环。
fast=fast.next.next;
slow=slow.next;
if(fast==slow){//相遇点
ListNode p1=head;
ListNode p2=fast;
while(p1!=p2){//未到入口点
p1=p1.next;
p2=p2.next;
}
return p1;
}
}
return null;
}
}