双指针是处理数组原地操作的高效技巧,核心为一指针遍历、一指针标记目标位置,时间复杂度o(n);适用于去重(保留1个或k个)、移动零、合并有序数组等场景,均通过合理设计指针逻辑实现原地操作。

双指针是处理数组原地操作的高效技巧,尤其适合去重和元素移动类问题——核心在于用一个指针遍历,另一个指针标记目标位置,避免额外空间,时间复杂度稳定为 O(n)。
原地删除重复元素(保留1个)
适用于已排序数组,要求不使用额外数组,返回去重后长度。
思路:left 指向已确定的无重区域末尾,right 逐个扫描。当 nums[right] ≠ nums[left] 时,把 nums[right] 赋给 nums[++left]。
示例代码逻辑:
- 初始化 left = 0,right 从 1 开始遍历
- 遇到不同值就前移 left 并赋值,相同则跳过
- 最终长度为 left + 1(因为下标从 0 开始)
删除重复元素(最多保留 k 个)
通用化上一题,比如“每个元素最多出现两次”,关键在判断是否已达上限。
技巧:不直接比较 nums[right] 和 nums[left],而是和 nums[left - k + 1] 比——即当前窗口允许的最左边界值。
操作步骤:
- 若 k = 2,允许重复一次,那么只要 nums[right] ≠ nums[left - 1],就可放入
- left 初始为 k - 1,right 从 k 开始;或统一设 left = 0,用计数器辅助也行
- 更稳健做法:每次赋值后 left++,仅当新元素满足条件才推进
移动零到末尾(保持非零元素顺序)
本质是“按条件分区”:把非零元素挪到前面,剩余位置补零。
双指针分工明确:
- write 指针指向下一个待填入非零元素的位置
- read 指针遍历整个数组,遇到非零就 nums[write++] = nums[read]
- 遍历完后,从 write 开始到末尾全部置为 0
注意:该方法不交换、不打乱顺序,比多次 swap 更清晰可靠。
合并两个有序数组(原地,nums1 有足够空位)
经典场景:nums1 长度为 m+n,后 n 位为空,nums2 长度为 n。要求合并后仍有序。
关键:从后往前双指针,避免覆盖 nums1 前部元素。
- 设 i = m-1(nums1 有效尾)、j = n-1(nums2 尾)、k = m+n-1(nums1 总尾)
- 每次取较大者填入 nums1[k],对应指针前移
- 若 nums2 先遍历完,无需处理;若 nums1 先完,把剩余 nums2 元素拷贝过去










