Skip to content

双指针法是一种常用且有效的算法技巧,主要用于数组、链表等线性数据结构的处理,我们来系统地梳理一下:

  1. 双指针法的基本概念

双指针法使用两个指针在(线性)数据结构中移动,以完成特定任务。根据移动方向和起始位置,可以分为以下几类:

  • 同向双指针(快慢指针)
  • 相向双指针
  • 背向双指针
  1. 同向双指针(快慢指针)
  • 两个指针从同一侧开始,通常都从左侧开始。
  • 一个指针移动较快,另一个指针移动较慢。
  • 常用于解决数组中的重复元素、链表中的循环检测等问题。

示例: 删除排序数组中的重复项

python
from typing import List


def remove_duplicates(nums: List[int]) -> int:
    if len(nums) == 0:
        return 0

    slow = 0
    for fast in range(1len(nums)):
        if nums[fast] != nums[slow]:
            slow += 1
            nums[slow] = nums[fast]

    return slow + 1

示例:删除链表中指定的元素项

go
/**
 * Definition for singly-linked list.
 * type ListNode struct {
 *     Val int
 *     Next *ListNode
 * }
 */
func removeElements(head *ListNode, val int) *ListNode {
    dummy := &ListNode{Next: head}
    prev := dummy
    curr := prev.Next
    for curr != nil {
        if curr.Val == val {
            prev.Next = curr.Next
        } else {
            prev = curr
        }
        curr = curr.Next
    }
    return dummy.Next
}

示例:给你一个数组 nums 和一个值 val,你需要原地移除所有数值等于 val 的元素,元素的顺序可能发生改变,然后返回 nums 中与 val 不同的元素的数量。

go
func removeElements(nums []int, val int) int {
		fast := 0
		slow := fast
		for fast < len(nums) {
			if nums[fast] != val {
				nums[slow] = nums[fast]
				slow++
			}
			fast++
		}
		return slow
}
  1. 相向双指针
  • 两个指针分别从数组的两端向中间移动
  • 常用于排序数组的搜索、求和问题等

示例: 两数之和 II - 输入有序数组

python
from typing import List


def two_sum(nums: List[int], target: int) -> List[int]:
    left, right = 0, len(nums) - 1

    while left < right:
        current_sum = nums[left] + nums[right]
        if current_sum == target:
            return [left + 1, right + 1]
        elif current_sum < target:
            left += 1
        else:
            right -= 1

    return []  # 未找到符合条件的两个数
  1. 背向双指针
  • 两个指针从中间向两端移动
  • 常用于寻找最长回文子串等问题

示例: 最长回文子串

python
def longest_palindrome(s: str) -> str:
    def expand_around_center(left, right):
        while left >= 0 and right < len(s) and s[left] == s[right]:
            left -= 1
            right += 1
        return s[left+1:right]

    result = ""
    for i in range(len(s)):
        # 奇数长度回文
        odd = expand_around_center(i, i)
        # 偶数长度回文
        even = expand_around_center(i, i+1)
        result = max(result, odd, even, key=len)

    return result
  1. 使用双指针的技巧
  • 明确指针的含义和移动条件
  • 注意边界条件的处理
  • 在循环中正确地更新指针
  • 考虑特殊情况(如空数组、单元素数组等)
  1. 常见应用场景
  • 数组/字符串的原地操作
  • 滑动窗口问题
  • 链表操作(如找中点、检测环)
  • 回文串问题
  • 归并两个有序数组

双指针法的核心在于利用问题的特性,通过巧妙设置和移动两个指针来降低时间复杂度,通常可以将暴力解法的 O(n^2) 优化到 O(n)。