0 总结
双指针:分别指向两个链表,每个链表各自一个指针
快慢指针:指向同一个链表,一前一后,前进速度不同
相遇指针:指向同一个有环链表,一前一后,前进速度不同
1 获取 倒数第k个元素
1.1 题目
面试题22. 链表中倒数第k个节点
https://leetcode-cn.com/problems/lian-biao-zhong-dao-shu-di-kge-jie-dian-lcof
1.2 快慢指针
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public ListNode getKthFromEnd(ListNode head, int k) {
if(k <= 0) return null; // 鲁棒性:k<=0
ListNode fast = head;
ListNode slow = head;
while(fast != null && k > 0){
fast = fast.next;
k--;
}
while(fast != null && k == 0){
fast = fast.next;
slow = slow.next;
}
if(k != 0) return null; // 鲁棒性:head没有k那么长
return slow;
}
}
2 获取 链表的中间节点
2.1 题目
- 链表的中间结点
获取链表中间的元素,若节点数为奇数 2n,获取第 n+1 个节点
https://leetcode-cn.com/problems/middle-of-the-linked-list/
2.2 快慢指针
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public ListNode middleNode(ListNode head) {
ListNode slow = head;
ListNode fast = head;
while(fast.next != null){
slow = slow.next;
if(fast.next.next == null) break;
fast = fast.next.next;
}
return slow;
}
}
3 判断 链表是否存在环
3.1 题目
- 环形链表
https://leetcode-cn.com/problems/linked-list-cycle/
3.2 相遇指针
/**
* Definition for singly-linked list.
* class ListNode {
* int val;
* ListNode next;
* ListNode(int x) {
* val = x;
* next = null;
* }
* }
*/
public class Solution {
public boolean hasCycle(ListNode head) {
if(head == null || head.next == null) return false;
ListNode slow = head;
ListNode fast = head.next;
// 两指针未相遇,循环
while(slow != fast){
if(fast.next == null || fast.next.next == null) return false;
// 指针1移动
slow = slow.next;
// 指针2移动
fast = fast.next.next;
}
return true;
}
}
4 判断 环的长度
4.1 题目
判断链表内环的长度
4.2 相遇指针
快慢指针相遇后继续移动,直到第二次相遇。两次相遇间的移动次数即为环的长度
public class Solution {
public int cycleLength(ListNode head) {
if(head == null || head.next == null) return false;
ListNode slow = head;
ListNode fast = head.next;
// 第一次循环至两指针相遇
while(slow != fast){
if(fast.next == null || fast.next.next == null) return -1; // 代表不存在环
// 指针1移动
slow = slow.next;
// 指针2移动
fast = fast.next.next;
}
// 第二次循环至两指针相遇
int length = 0;
while(slow != fast){
// 指针1移动
slow = slow.next;
// 指针2移动
fast = fast.next.next;
// 记录长度
length++;
}
return length;
}
}
5 获取 相交节点
5.1 题目
面试题52. 两个链表的第一个公共节点
(160. 相交链表)
https://leetcode-cn.com/problems/intersection-of-two-linked-lists/
5.2 相遇指针
/**
* 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 A = headA;
ListNode B = headB;
// 两指针未相遇,循环
while(A != B){
// 指针1移动
if(A == null) A = headB; // 必须遍历到null再换B遍历,这样AB各一遍就结束了(同指向null,表明没有交点)。如果遍历到A末尾就直接换B,导致不停的ABAB循环多次
else A = A.next;
// 指针2移动
if(B == null) B = headA;
else B = B.next;
}
return A;
}
}
6 合并(串接) 2个有序链表
6.1 题目
面试题25. 合并两个排序的链表
21. 合并两个有序链表
https://leetcode-cn.com/problems/he-bing-liang-ge-pai-xu-de-lian-biao-lcof
6.2 双指针
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
ListNode head = new ListNode(0);
ListNode l = head;
// 经典的双指针 while if else
while(l1 != null && l2 != null){
if(l1.val <= l2.val){
l.next = l1;
l1 = l1.next;
}
else{
l.next = l2;
l2 = l2.next;
}
l = l.next;
}
l.next = (l1 != null) ? l1 : l2;
return head.next;
}
}