前言
基于数据结构的扎实基础,算法思想能够有效提升问题解决的效率。双指针是一种简洁、高效且应用广泛的解题思想,它并非局限于字面意义上的两个指针,而是通过设置两个'标记点'(索引),协同遍历、筛选或修改数据,从而简化问题复杂度。
无论是数组、链表的遍历处理,还是数值组合、环形问题的求解,双指针都能发挥其独特优势——相较于暴力枚举的多层循环,它往往能将时间复杂度从 O(n²) 优化至 O(n),大幅提升代码运行效率,同时让解题逻辑更清晰。本文将系统拆解双指针算法的核心逻辑,结合经典例题,从算法思想、解题步骤、代码实现三个维度,带你掌握双指针的用法。
什么是双指针
需要说明的是,双指针并不局限于字面意义上的内存指针,更多时候是指数组或链表中的索引下标。核心在于利用两个目标点的相对运动来简化问题。
快慢双指针
算法思想
前后快慢指针通常以慢指针为基准划分界限:慢指针左侧(包括其指向的元素)满足特定条件,右侧则不满足;或者用于检测链表环等场景。
快排思想示例
快速排序最初由霍尔提出,逻辑相对复杂。为了便于理解,我们可以用前后指针法来实现分区逻辑。
注:本文提到的'指针'在数组操作中通常指代索引下标。
- key:基准值
- prev:慢指针
- cur:快指针
- 首先选择最左侧元素作为基准值 key,初始化 prev 指针与 key 同位置,cur 指针指向下一个位置。
- 当 cur 指向的元素小于 key 时,移动 prev 指针并与 cur 进行元素交换。
- cur 指针持续移动,遇到比基准值小的元素时暂停,此时移动 prev 指针并进行交换。
- 重复上述过程直到 cur 指针越界。
- 最后交换 key 与 prev 指向的元素,确保基准值左侧元素均小于它,右侧元素均大于它。
// 双指针法快排分区
int partition(int* a, int left, int right) {
int keyi = left;
int prev = left, cur = left + 1;
while (cur <= right) {
if (a[cur] < a[keyi]) {
prev++;
if (a[cur] != a[prev]) {
Swap(&a[cur], &a[prev]);
}
}
cur++;
}
Swap(&a[keyi], &a[prev]);
return prev;
}
至此完成对基准值的排序,之后只需递归地对左右两个子区间执行相同操作,即可完成整个数组的排序。
移动零(保持顺序)
题目要求将数组中的所有 0 移动到末尾,且保持非零元素的相对顺序。这可以类比为以零为基准的单次快速排序。


