1. 双指针算法
在数据结构链表和顺序表的学习中,我们已经使用过双指针的算法思想。例如删除数组中的重复元素、判断链表是否为环、找出链表的中间节点等。
常见的双指针有两种形式,一种是对撞指针,一种是左右指针。
- 对撞指针:一般用于顺序结构中。一个指针从最左端开始,另一个从最右端开始,逐渐往中间逼近。终止条件一般是两个指针相遇(
left == right)或者错开(left > right)。- 快慢指针:又称为龟兔赛跑算法。基本思想是使用两个移动速度不同的指针在数组或链表等序列结构上移动。最常用的方式是在一次循环中,每次让慢的指针向后移动一位,而快的指针往后移动两位。这种方法对于处理环形链表或数组非常有用。
2. 双指针在算法题内的使用
2.1 移动零
题目解析
将数组内的所有零都移动到非零元素之后,并且保持所有非零元素的相对位置不变。
示例:输入 [1,0,3,12],输出 [1,3,12,0,0]。
算法原理讲解
该题属于数组分块类型,特征是将数组划分为几个区间。适合使用双指针解决。在数组中使用双指针时,指针通常用数组下标表示。
思路:
创建两个数组下标 cur 和 dest。cur 从左往右遍历数组,dest 指向已处理区间内的最后一个非零元素。数组可划分为三个区间:[0, dest](非零)、[dest+1, src-1](零)、[src, n-1](待遍历)。最终当 src 遍历到末尾时,剩余部分补零。
流程:
- 当
cur位置元素为 0 时,只让cur++。 - 当
cur位置元素不为 0 时,先让dest++,再交换dest和cur位置的元素。
代码实现
class Solution {
public:
void moveZeroes(vector<int>& nums) {
int dest = -1;
for(int src = 0; src < nums.size(); src++) {
if(nums[src] != 0 && ++dest != src) {
swap(nums[src], nums[dest]);
}
}
}
};


