双指针经典算法题实战解析
双指针是处理数组和链表问题的高效技巧,核心在于利用两个指针的相对运动来减少时间复杂度。下面结合几道经典题目,聊聊其中的设计思路与边界细节。
1. 移动零 (Move Zeroes)
题目链接: LeetCode 283
这道题的目标是将数组中的 0 移动到末尾,同时保持非零元素的相对顺序。最直观的思路是用双指针将数组划分为三个区间:已处理的非零区、待处理的零区、未处理区。
我们可以维护一个 dest 指针指向非零区的末尾,初始为 -1;cur 指针遍历数组。当 cur 遇到非零元素时,先扩展非零区(++dest),再交换 dest 和 cur 的值。如果 cur 遇到 0,则直接跳过,让它留在零区。
def moveZeroes(nums):
dest = -1
for cur in range(len(nums)):
if nums[cur] != 0:
dest += 1
nums[dest], nums[cur] = nums[cur], nums[dest]
注意,循环结束时 cur 会遍历完整个数组,此时所有非零元素都已按序前移,剩余位置自然填充为 0。
2. 复写零 (Duplicate Zeros)
题目链接: LeetCode 1089
如果直接从前往后模拟复写 0,后面的数据会被覆盖。因此,更稳妥的策略是从后往前操作。
我们需要先确定最后一个需要复写的数字位置。可以设 cur 从头开始,dest 从逻辑上的末尾开始(考虑复写后的长度)。当 cur 遇到 0 时,dest 走两步并标记为 0;遇到非 0 时,dest 走一步复制值。
这里有个关键点:dest 可能会走到原数组范围之外,这通常意味着最后一个 0 被截断了,需要单独处理边界情况。实际编码时,建议先计算有效长度,再倒序填充。
3. 快乐数 (Happy Number)
题目链接: LeetCode 202
判断一个数是否为快乐数,本质上是检测数字变换过程中是否存在环。无论结果是 1 还是进入死循环,最终都会形成闭环。
使用快慢指针法:定义一个函数计算数字各位平方和。快指针每次运算两次,慢指针每次运算一次。如果存在环,两者必会相遇。相遇时若值为 1,则是快乐数;否则不是。
def get_next(n):
total_sum =
n > :
n, digit = (n, )
total_sum += digit **
total_sum
():
slow = n
fast = get_next(n)
fast != slow != fast:
slow = get_next(slow)
fast = get_next(get_next(fast))
fast ==


