【双指针——移动零】数组划分类题目的入门基石

一、双指针概述

双指针是算法题中非常经典的解题思想,核心是通过两个指针协同遍历,在一次遍历内完成目标,通常可以把暴力解法的时间复杂度从 O (n²) 优化到 O (n)。常见的双指针分为两大类:对撞指针、快慢指针。

1. 对撞指针(左右指针)

对撞指针多用于数组这类顺序结构,也常被称为左右指针。

  • 两个指针分别从数组的两端出发,左指针从最左侧开始,右指针从最右侧开始,逐步向中间逼近。
  • 循环的终止条件一般是两个指针相遇(left == right),或者两个指针错开(left > right);也可能在循环内部找到目标结果后直接跳出循环。

2. 快慢指针(龟兔赛跑算法)

快慢指针的核心思想,是使用两个移动速度不同的指针,在数组、链表等顺序结构上移动。

  • 这种方法最经典的应用场景是判断环形链表、寻找环入口。
  • 不止是环形结构,只要问题中存在循环往复的特征,都可以考虑用快慢指针的思路来解决。
  • 最常用的实现方式:在一次循环中,慢指针每次向后移动一步,快指针每次向后移动两步,通过一快一慢的速度差来识别循环。

二、例题:移动零(LeetCode 283,难度:Easy)

这是一道非常经典的「数组分两块」题型,核心是按照指定规则,把数组元素划分成左右两部分。这类区间划分的题目,通常都可以用双指针的思路高效解决。

题目描述

解法思路:快排划分思想(数组分两块)

这道题可以借鉴快速排序中的区间划分思想:用两个指针维护两个区间,一个是非零元素区间,一个是零元素区间,一次遍历完成划分。

核心思想

定义两个指针:

  • cur:遍历指针,用来扫描整个数组的每一个元素
  • dest:标记非零元素序列的最后一个位置

在 cur 遍历的全程,始终维持一个不变量:

[0, dest] 区间内的元素全部是非零元素; [dest + 1, cur - 1] 区间内的元素全部是 0。

根据 cur 遇到的元素不同,分情况处理,最终就能把所有非零元素留在左边,所有零移到右边。

算法流程

初始化

  1. cur = 0,从数组第一个元素开始遍历
  2. dest = -1,初始时非零区间还不存在,所以非零末尾位置初始化为 -1

遍历处理 cur 依次向后遍历每一个元素,分两种情况处理:

  1. 遇到元素为 0 :cur 直接向后移动一位即可。 因为我们的目标是让 [dest+1, cur-1] 全是 0,cur 遇到 0 时自增,这个 0 自然就落在了零区间内。
  2. 遇到元素非 0 :先让 dest 自增 1,然后交换 cur 位置和 dest 位置的元素,之后 cur 再向后移动一位。
  • dest 原本指向非零区间的末尾,新发现一个非零元素,它的位置应该在 dest+1,所以 dest 先加 1;
  • dest++ 之后指向的元素原本是 0,和 cur 位置的非零元素交换后,新的非零元素就被纳入了非零区间,0 被换到了零区间,两个区间的性质始终保持不变。

C++ 代码实现

复制代码
class Solution {
public:
    void moveZeroes(vector<int>& nums) {
        // cur 遍历整个数组,dest 标记非零区间的末尾位置
        for(int cur = 0, dest = -1; cur < nums.size(); cur++)
        {
            // 遇到非零元素,将其交换到非零区间末尾
            if(nums[cur])
            {
                swap(nums[++dest], nums[cur]);
            }
        }
    }
};

复杂度分析

  • 时间复杂度:O (n),仅遍历数组一次
  • 空间复杂度:O (1),只使用常数个额外变量,全程原地修改数组

补充:这道题的双指针属于同向快慢指针的变体,两个指针都向右移动、速度不同,是双指针体系里非常基础的模板题。

同一道算法题,解法往往不唯一。这里分享的只是我个人的思路与实现,供大家参考。大家也可以顺着自己的想法去尝试不同的写法,如果有更优的解法或是不一样的理解,欢迎在评论区留言交流,我们一起探讨、共同进步。

相关推荐
·present·3 小时前
CSAPP(Bomb lab)
c语言·c++
王老师青少年编程3 小时前
2026年信奥赛c++普及组csp-j第二轮复赛真题
c++·真题·csp·信奥赛
深圳市快瞳科技有限公司4 小时前
野外鸟类AI识别落地实录:输入适配、结构化输出、去重聚合与置信度分流的工程实践
算法·计算机视觉·鸟类识别·鸟类ai识别·野外鸟类观测·林业调查
时间的拾荒人4 小时前
CMake 常用命令详解:从版本声明到安装部署
c++·面试
专注仿真5 小时前
梯度提升类(XFBoost)算法详解与代码实例
开发语言·人工智能·python·算法·大模型训练·控制算法
小豆庄5 小时前
视频遮罩追踪退场后ID撞号的排查—多目标场景下的失效
opencv·算法·bug·视频·python3.11
Tisfy6 小时前
LeetCode 3882.网格图中最小异或路径:动态规划
算法·leetcode·动态规划
D e re k ZH7 小时前
P5025 [SNOI2017] 炸弹
c++·算法
A boy CDEF girl7 小时前
算法题专栏:优选算法
数据结构·算法·leetcode