24. 两两交换链表中的节点
题目的大题步骤是如下图:
循环的条件如果是奇数个结点的话,那么最后一个结点不用考虑,cur.next.next==null,如果是偶数个结点,那么cur.next==null,注意每次都让cur指向移动结点的前一个结点才能进行操作。
进行操作的过程记得提前保存cur.next和和cur.next.next.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 swapPairs(ListNode head) {
ListNode dummyhead=new ListNode();
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;
cur.next.next=temp;
//换成下面这句也可以
//temp.next.next=temp;
temp.next=temp1;
cur=cur.next.next;//cur的指向操作数的前一个位置
}
return dummyhead.next;
}
}
19.删除链表的倒数第N个节点
双指针
如何找到倒数第n个结点的值是关键,双指针思想,让快指针先移动n+1个位置(注意不是n),这时候再同时移动两个指针,慢指针就来到了第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) {
// 快慢指针,快指针移动n+1步,慢指针再跟着一起移动
ListNode dummyhead = new ListNode();
dummyhead.next=head;
ListNode fast = dummyhead;
ListNode slow = dummyhead;
for (int i= 0; i <= n; i++) {
fast = fast.next;
}
while (fast != null) {//当快指针指到末尾,慢指针恰好指向n-1的位置
fast = fast.next;
slow= slow.next;
}
slow.next = slow.next.next;
return dummyhead.next;
}
}
面试题 02.07. 链表相交
快慢指针
判断链表的指针是否有交点,重要是看有没有结点相等,也就是headA==headB,而不是仅仅headA.val==headB.val。首先需要找到开始比较的位置,由于两个链表长度不一样,所以让长的链表先移动两个链表长度的差值,然后两个链表长度相等了再一起移动进行判断。
再进行长度比较时需要记录两个链表长度的差值,并根据此移动较长的链表,所以可以选链表A为最长的链表,如果链表B比A长,就让A和B交换,始终保持链表A是最长的。
/**
* 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 cur0 = headA;
ListNode cur1 = headB;
// 计算链表A的长度
while (cur0 != null) {// 计算的时候可以不使用cur.next,而是直接用cur
cur0 = cur0.next;
sizeA++;
}
// 计算链表B的长度
while (cur1 != null) {
cur1 = cur1.next;
sizeB++;
}
ListNode curA = headA;
ListNode curB = headB;
if (sizeB > sizeA) {
ListNode temp1 = curA;
curA = curB;
curB = temp1;
int temp = sizeA;
sizeA = sizeB;
sizeB = temp;
}
int size = sizeA - sizeB;
for (int i = 0; i < size; i++) {
curA = curA.next;
}
while (curA != null) {
if (curA == curB) {// 注意不是值相等,而是结点相等
return curA;
}
curA = curA.next;
curB = curB.next;
}
return null;
}
}
142.环形链表II
双指针
判断链表中是否有环,采用快慢指针,fast一次走两步,slow一次走一步,如果有环,fast指针最后一定会追上slow指针。结论是相遇时刻离进入环的距离和head指针离环开始的地方的距离相等,所以在定义两个指针来判断一起到达环起始的位置即为环开始的结点。
/**
* 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) {
fast = fast.next.next;
slow = slow.next;
// 相遇了
if (fast == slow) {
ListNode index1 = head;
ListNode index2 = fast;// 相遇位置
while (index1 != index2) {
index1 = index1.next;
index2 = index2.next;
}
return index1;
}
}
return null;
}
}