/**
* 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 dummyhead = new ListNode(-1);
dummyhead.next = head;
ListNode cur = dummyhead;
ListNode tmp;
ListNode firstNode;
ListNode secondNode;
while(cur.next != null && cur.next.next!=null){
tmp = cur.next.next.next;
firstNode = cur.next;
secondNode = cur.next.next;
//step 1
cur.next = secondNode;
//step 2
secondNode.next = firstNode;
//step 3
firstNode.next = tmp;
//cur最后移动,准备下一轮交换
cur = firstNode;
}
return dummyhead.next;
}
}
-
创建一个虚拟头节点:
- 使用虚拟头节点
dummyhead
可以简化边界条件,无需分别处理头节点和其他节点。
- 使用虚拟头节点
-
初始化指针:
cur
指针用于追踪当前需要交换的对的前一个节点。一开始指向dummyhead
。firstNode
和secondNode
分别指向需要交换的两个节点。tmp
用于临时存储第二节点后的节点。
-
交换操作:
- 首先检查
cur
后是否有两个节点可以交换。 - 使用
tmp
存储secondNode
后的节点。 - 进行三个交换步骤:
- 将
cur.next
指向secondNode
。 - 将
secondNode.next
指向firstNode
。 - 将
firstNode.next
指向tmp
。
- 将
- 最后,将
cur
指针移动到firstNode
,为下一对节点做准备。
- 首先检查
-
返回结果:
- 返回
dummyhead.next
,它是交换后链表的新头节点。
- 返回
/**
* 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) {
ListNode dummyhead = new ListNode(0);
dummyhead.next = head;
//定义两个指针
ListNode fastIndex = dummyhead;
ListNode slowIndex = dummyhead;
for(int i = 0; i <n; i++){
fastIndex = fastIndex.next;
}
while(fastIndex.next!=null){
fastIndex = fastIndex.next;
slowIndex = slowIndex.next;
}
//此时slowindex就是待删除的前一个元素
slowIndex.next = slowIndex.next.next;
return dummyhead.next;
}
}
思路:
关键是找到待删除元素的前一个元素
-
创建一个虚拟头节点:
- 使用虚拟头节点
dummyhead
可以简化边界条件,无需分别处理头节点和其他节点。例如,当链表只有一个节点或需要删除头节点时,这一点是非常有用的。
- 使用虚拟头节点
-
初始化双指针:
fastIndex
和slowIndex
两个指针均从dummyhead
开始。- 先移动
fastIndex
指针,使它领先slowIndex
指针 n 步。
-
同时移动两个指针:
- 当
fastIndex
和slowIndex
之间的间隔为 n 时,同时移动两个指针,直到fastIndex
到达链表末尾。 - 此时,
slowIndex
指向待删除节点的前一个节点。
- 当
-
删除节点:
- 通过
slowIndex.next = slowIndex.next.next
来跳过待删除的节点,从而删除它。
- 通过
-
返回结果:
- 返回
dummyhead.next
,这是修改后链表的新头节点。
- 返回
/**
* 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) {
ListNode curA = headA;
ListNode curB = headB;
int lenA = 0, lenB = 0;
while(curA!=null){
lenA++;
curA = curA.next;
}
while(curB != null){
lenB++;
curB = curB.next;
}
curA = headA;
curB = headB;
if(lenB>lenA){
int temp = lenA;
lenA = lenB;
lenB = temp;
ListNode tmp = curA;
curA = curB;
curB = tmp;
}
int gap = lenA - lenB;
while(gap>0){
gap--;
curA = curA.next;
}
while(curA!=null){
if(curA == curB){
return curA;
}
curA = curA.next;
curB = curB.next;
}
return null;
}
}
思路:
-
计算两个链表的长度:
- 遍历链表A和B,分别计算它们的长度为
lenA
和lenB
。
- 遍历链表A和B,分别计算它们的长度为
-
找到长链表的起始点:
- 如果链表A比链表B长,则链表A的当前节点(
curA
)应向前移动lenA - lenB
步,反之亦然。这样,两个链表就可以在同一起始点上对齐。
- 如果链表A比链表B长,则链表A的当前节点(
-
寻找交点:
- 现在,两个链表的长度相同,所以可以同时遍历两个链表,查看它们的节点是否相同。如果在遍历过程中找到相同的节点,那么这个节点就是交点。
- 如果遍历结束都没有找到相同的节点,那么两个链表没有交点,返回
null
。
此方法利用了“对齐”技巧。当两个链表的长度不同,且有交点时,那么较长链表的前几个节点不可能是交点。所以,可以安全地跳过它们,从而使两个链表长度相同。
这种方法的优势在于只需要遍历两次链表。第一次是计算长度,第二次是寻找交点。
/**
* 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 fastIndex = head;
ListNode slowIndex = head;
while(fastIndex!=null && fastIndex.next!=null){
fastIndex = fastIndex.next.next;
slowIndex = slowIndex.next;
if(slowIndex == fastIndex) { //相遇,证明有环
ListNode index1 = fastIndex;
ListNode index2 = head;
// 两个指针,从头结点和相遇结点,各走一步,直到相遇,相遇点即为环入口
while(index1 != index2){
index1 = index1.next;
index2 = index2.next;
}
return index1;
}
}
return null;
}
}
思路:
-
查找环:使用两个指针,一个快指针每次移动两个节点,一个慢指针每次移动一个节点。如果链表中存在一个环,那么快指针和慢指针最终会在某个节点上相遇。
-
查找环的入口:当快指针和慢指针相遇时,把快指针或慢指针重新放回头节点,然后每次移动快指针和慢指针一个节点,当它们再次相遇时,相遇的节点就是环的入口。
-
首先,定义两个指针
fastIndex
和slowIndex
,都初始化为头节点head
。 -
然后,通过一个
while
循环,使得fastIndex
指针每次向前移动两个节点,而slowIndex
指针每次向前移动一个节点。这是在寻找环的步骤。 -
如果存在一个环,
fastIndex
指针和slowIndex
指针最终会相遇(在环内的某个位置)。 -
当它们相遇时,你把其中一个指针(代码中是 slow
Index
)重新设置为头节点。然后,再次移动两个指针,但这次每个指针都只移动一个节点,直到它们相遇。当它们相遇时,相遇的节点就是环的入口。 -
如果
fastIndex
和fastIndex.next
中的任何一个为null
,这意味着链表没有环,因此返回null
。