1. 快慢指针(起点不一致)
起点不一致的快慢指针:快指针先走 n 步,然后两个指针同时移动,快指针到达末尾时,慢指针正好在目标位置。
- 初始化:两个指针 slow、fast 都指向头节点。
- 快指针先行:快指针先移动 n 步。
- 同步移动:两个指针同时移动,直到快指针到达末尾(
fast == Null)。 - 结果:慢指针正好指向倒数第 n 个节点
模板:
def findNthFromEnd(head, n): slow = fast = head # 快指针先走 n 步 for _ in range(n): fast = fast.next # 两个指针同时移动 while fast: slow = slow.next fast = fast.next return slow # 慢指针指向倒数第 n 个节点例题:19. 删除链表的倒数第 N 个结点 - 力扣(LeetCode)
注意:链表删除节点 → 一律用 dummy 虚拟头节点这样永远不会空指针,永远能删头节点!
给你一个链表,删除链表的倒数第n个结点,并且返回链表的头结点。
示例 1:
输入:head = [1,2,3,4,5], n = 2输出:[1,2,3,5]
/** * Definition for singly-linked list. * public class ListNode { * public int val; * public ListNode next; * public ListNode(int val=0, ListNode next=null) { * this.val = val; * this.next = next; * } * } */ public class Solution { public ListNode RemoveNthFromEnd(ListNode head, int n) { 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.next!=null) { fast=fast.next; slow = slow.next; } slow.next = slow.next.next; return dummyHead.next; } }2. 快慢指针(步长不一致)
步长不一致的快慢指针:两个指针从同一起点出发,慢指针每次走 1 步,快指针每次走 2 步。
- 初始化:两个指针都指向头节点。
- 不同步长:慢指针每次移动 1 步,快指针每次移动 2 步。
- 终止条件:快指针到达末尾或无法继续移动。
- 应用场景:找中点、检测环、找交点等。
模板:
def fastSlowPointer(head): slow = fast = head # 快指针每次走 2 步,慢指针每次走 1 步 while fast and fast.next: slow = slow.next # 慢指针移动 1 步 fast = fast.next.next # 快指针移动 2 步 return slow # 慢指针指向中点或环的入口
例题:876. 链表的中间结点 - 力扣(LeetCode)
给你单链表的头结点head,请你找出并返回链表的中间结点。
如果有两个中间结点,则返回第二个中间结点。
示例 1:
输入:head = [1,2,3,4,5]输出:[3,4,5]解释:链表只有一个中间结点,值为 3 。
示例 2:
输入:head = [1,2,3,4,5,6]输出:[4,5,6]解释:该链表有两个中间结点,值分别为 3 和 4 ,返回第二个结点。
/** * Definition for singly-linked list. * public class ListNode { * public int val; * public ListNode next; * public ListNode(int val=0, ListNode next=null) { * this.val = val; * this.next = next; * } * } */ public class Solution { public ListNode MiddleNode(ListNode head) { ListNode fast = head; ListNode slow = head; while(fast!=null&&fast.next!=null) { fast = fast.next.next; slow=slow.next; } return slow; } }3. 分离双指针
分离双指针:两个指针分别在不同的链表中移动,常用于合并、比较等操作。
- 初始化:两个指针分别指向两个链表的头节点。
- 条件移动:根据具体问题决定何时移动哪个指针。
- 终止条件:其中一个链表遍历完毕或满足特定条件。
- 应用场景:有序链表合并、链表比较等。
模板:
def separateTwoPointers(list1, list2): p1, p2 = list1, list2 while p1 and p2: if condition1: # 两个指针同时移动 p1 = p1.next p2 = p2.next elif condition2: # 只移动第一个指针 p1 = p1.next else: # 只移动第二个指针 p2 = p2.next return result例题:21. 合并两个有序链表 - 力扣(LeetCode)
将两个升序链表合并为一个新的升序链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。
示例 1:
输入:l1 = [1,2,4], l2 = [1,3,4]输出:[1,1,2,3,4,4]
/** * Definition for singly-linked list. * public class ListNode { * public int val; * public ListNode next; * public ListNode(int val=0, ListNode next=null) { * this.val = val; * this.next = next; * } * } */ public class Solution { public ListNode MergeTwoLists(ListNode list1, ListNode list2) { ListNode dummyHead = new ListNode(); ListNode current = dummyHead; while(list1!=null&&list2!=null) { if(list1.val<=list2.val) { current.next =list1; list1 = list1.next; } else { current.next = list2; list2 = list2.next; } current = current.next; } if(list2!=null) { current.next = list2; } else { current.next =list1; } return dummyHead.next; } }