两两交换链表中的节点
题目链接:24. 两两交换链表中的节点
解题思路:画图,弄清楚节点之间的指向改变,弄清楚循环的终止条件和需要临时保存的节点。最后确定循环中cur指针的移动。
class Solution {
public ListNode swapPairs(ListNode head) {
//定义虚拟头结点并指定其next指针为head
ListNode dummyhead = new ListNode(0);
dummyhead.next = 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;//步骤1,由虚拟头结点指向2节点
cur.next.next = temp;//步骤2,由2节点指向1节点
temp.next = temp1;//步骤3,由1节点指向3节点
//移动cur指针
cur = cur.next.next;
}
return dummyhead.next;
}
}
删除链表中的倒数第N个节点
题目链接:19. 删除链表的倒数第 N 个结点
解题思路:画图,利用快慢指针,先找到要删除节点的前驱节点
- 先让快指针移动n+1步后,让快慢指针同时移动
- 当快指针移动到空节点时,慢指针正好移动到要删除节点的前一个节点
- 让慢指针的slow.next = slow.next.next,删除该元素
class Solution {
public ListNode removeNthFromEnd(ListNode head, int n) {
ListNode dummyhead = new ListNode(0);
dummyhead.next = head;
ListNode fast = dummyhead;
ListNode slow = dummyhead;
n++;
//先让快指针移动n+1步
while(n-->0 && fast != null){
fast = fast.next;
}
//快慢指针同时移动到快指针指到null
while(fast != null){
fast = fast.next;
slow =slow.next;
}
//找到了要删除节点的前一个节点位置即为slow
slow.next = slow.next.next;
return dummyhead.next;
}
}
相交链表
题目链接:160. 相交链表
解法一:走的长度相等时,最后相遇点即是交点
当p在A链表走到null时,从B链表开始走;
当q在B链表走到null时,从A链表开始走。
public class Solution {
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
ListNode p = headA;
ListNode q = headB;
while(p != q){
p = p != null ? p.next : headB;
q = q != null ? q.next : headA;
}
return p;
}
}
解法二:先计算两个链表的长度,将长链表先移动到和短链表相同的位置,然后判断两个节点是否相等。相等直接返回,不相等继续移动。
public class Solution {
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
ListNode curA = headA;
ListNode curB = headB;
// 求两个链表的长度
int lenA = 0;
int lenB = 0;
while(curA != null){
lenA++;
curA = curA.next;
}
while(curB != null){
lenB++;
curB = curB.next;
}
// 将指针重新指向头结点
curA = headA;
curB = headB;
// 让curA指向的是长链表
if(lenA < lenB){
int tempLen = lenA;
lenA = lenB;
lenB = tempLen;
ListNode tempNode = curA;
curA = curB;
curB = tempNode;
}
// 让curA移动和curB同时开始的位置
int gap = lenA - lenB;
while(gap-- > 0){
curA = curA.next;
}
// 判断,当curA和curB相等时,直接返回
while(curA != null){
if(curA == curB){
return curA;
}
curA = curA.next;
curB = curB.next;
}
return null;
}
}
环形链表Ⅱ
题目链接:142. 环形链表 II
主要考察两个知识点:
- 判断链表是否有环?定义两个快慢指针,快指针每次走两个单位,慢指针每次走一个单位,如果快慢指针相遇,说明有环。
- 如果有环,如何找到环的入口?快慢指针相遇后,一个指向相遇点,一个指向链表头结点,同时移动,两个指针相遇的点即是环的入口。
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 index1 = fast;
ListNode index2 = head;
while(index1 != index2){
index1 = index1.next;
index2 = index2.next;
}
return index1;
}
}
return null;
}
}