go中“双指针”实为两个整数索引l和r,用于切片遍历,与**int等指针无关;适用于已排序数组的两端操作问题,如两数之和、盛水最多等。

Go里“双指针”不是指针的指针,别被名字骗了
Go语言中所谓“双指针算法”,和 **int 这类二级指针完全无关——它只是用两个整数索引(l 和 r)在切片上移动的技巧。新手常因字面意思去查 &、* 用法,结果绕远路。
- 实际就是两个
int变量,比如left := 0、right := len(nums) - 1 - 所有操作都在切片索引层面,不涉及内存地址或取址解引用
- 如果你写了
var p *int再套一层**int,那是在做系统编程,不是双指针算法
什么时候该用左右对撞指针(l/r)
适用于已排序数组/切片,且目标与“两端值组合”相关的问题:比如两数之和、盛水最多、三数之和、回文判断。
- 典型信号:
nums已调用sort.Ints(nums);解空间具有单调性(如左小右大时 sum 偏小,就该动左指针) - 终止条件统一为
l ,不是 <code>l (否则可能重复计算单个元素) - 必须手动去重:遇到
nums[l] == nums[l+1]要跳过,否则threeSum会返回重复三元组
示例(找两数之和):
for l, r := 0, len(nums)-1; l sum := nums[l] + nums[r]<br> if sum == target { return []int{l, r} }<br> if sum }
快慢指针(slow/fast)专治“原地修改”和“链表环”
当你要边遍历边覆盖、或者处理无法随机访问的数据结构(如链表)时,快慢指针才是正解。
- 场景一(原地删元素):
removeElement(nums, val):用slow指向待填位置,fast扫描全部,只把非val的值拷过去 - 场景二(链表判环):Go 中虽无原生链表,但手写节点时,
fast = fast.Next.Next必须加nil判断,否则 panic:invalid memory address or nil pointer dereference - 性能关键:所有操作都在一次循环内完成,
O(n)时间 +O(1)空间,比新建切片省内存
容易忽略的边界和 panic 点
Go 的强类型和运行时检查会让双指针代码在边界出错时直接崩,而不是静默错位。
- 切片越界:用
r做索引前,务必确认r ,尤其在收缩后没重校验 - 空切片陷阱:
len(nums) == 0时,right := len(nums)-1会得-1,后续索引直接 panic - 整数溢出风险:算面积如
(r-l) * min(height[l], height[r]),若切片极长,r-l可能超int范围(不过 LeetCode 数据一般不触发)
最稳妥的习惯:所有指针更新后,立刻加 if l >= len(nums) || r 防御
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











