优选算法:01 双指针巧解移动零问题


🔥个人主页:K 旺仔小馒头

🍉学习方向:C/C++方向学习者

📖个人专栏:《C语言》《数据结构与算法》《C++知识分享》《C语言实战编程》《算法题从优选到贪心的解题技巧》

⭐️人生格言:‌"何时葡萄先熟透,你要静候再静候"



目录

前言:

双指针算法:

[1. 对撞指针:](#1. 对撞指针:)

[2. 快慢指针:](#2. 快慢指针:)

[01. 移动零](#01. 移动零)

[1.1 题目链接:](#1.1 题目链接:)

[1.2 题目描述:](#1.2 题目描述:)

[1.3 解法(快排的思想:数组划分区间-数组分两块):](#1.3 解法(快排的思想:数组划分区间-数组分两块):)

算法思路:

算法流程:

[1.4 C++算法代码:](#1.4 C++算法代码:)

[1.5 算法总结:](#1.5 算法总结:)

[1.6 手写笔记:](#1.6 手写笔记:)

结尾:


前言:

双指针算法是解决数组类问题的高效工具,其简洁的逻辑与较低的时间复杂度,使其成为算法学习中的重点内容。本文聚焦双指针的两种核心形式,以经典的 "移动零" 问题为切入点,结合快排分块思想,通过清晰的思路拆解、流程说明与 C++ 代码实现,带读者深入理解算法本质,为后续攻克复杂数据结构问题打下基础。


双指针算法:

常见的双指针有两种形式,一种是对撞指针,一种是快慢指针。

1. 对撞指针:

一般用于顺序结构中,也称左右指针。

  • 对撞指针从两端向中间移动。一个指针从最左端开始,另一个从最右端开始,然后逐渐往中间逼近。
  • 对撞指针的终止条件一般是两个指针相遇或者错开(也可能在循环内部找到结果直接跳出循环),也就是:left == right(两个指针指向同一个位置),left > right (两个指针错开)

2. 快慢指针:

又称为龟兔赛跑算法,其基本思想就是使用两个移动速度不同的指针在数组或链表等序列结构上移动。

这种方法对于处理环形链表或数组非常有用。 其实不单单是环形链表或者是数组,如果我们要研究的问题出现循环往复的情况时,均可考虑使用快慢指针的思想。 快慢指针的实现方式有很多种,最常用的一种就是:

  • 在一次循环中,每次让慢的指针向后移动一位,而快的指针往后移动两位,实现一快一慢。

01. 移动零

「数组分两块」是非常常见的一种题型,主要就是根据一种划分方式,将数组的内容分成左右两部分。这种类型的题,一般就是使用「双指针」来解决。

1.1 题目链接:

283. 移动零

1.2 题目描述:

1.3 解法(快排的思想:数组划分区间-数组分两块):

算法思路:
  • 在本题中,我们可以用一个cur 指针来扫描整个数组,另一个dest 指针用来记录非零数序列的最后一个位置。根据cur 在扫描的过程中,遇到的不同情况,分类处理,实现数组的划分。
  • cur 遍历期间,使**[0, dest]** 的元素全部都是非零元素, **[dest + 1, cur - 1]**的元素全是零。
算法流程:
  1. 初始化cur = 0 (用来遍历数组),dest = -1 (指向非零元素序列的最后一个位置。因为刚开始我们不知道最后一个非零元素在什么位置,因此初始化为**-1**)

  2. cur 依次往后遍历每个元素,遍历到的元素会有下面两种情况:

  1. 遇到的元素是0cur 直接 ++ 。因为我们的目标是让**[dest + 1, cur - 1]** 内的元素全都是零,因此当cur 遇到0 的时候,直接 ++ ,就可以让0cur - 1 的位置上,从而在**[dest + 1, cur - 1]**内;

  2. 遇到的元素不是0dest++ ,并且交换cur 位置和dest 位置的元素,之后让cur++ ,扫描下一个元素。

  • 因为dest 指向的位置是非零元素区间的最后一个位置,如果扫描到一个新的非零元素,那么它的位置应该在dest + 1 的位置上,因此dest 先自增1
  • dest++ 之后,指向的元素就是0 元素(因为非零元素区间末尾的后一个元素就是 0 ),因此可以交换到cur 所处的位置上,实现**[0, dest]** 的元素全部都是非零元素,**[dest + 1, cur - 1]**的元素全是零。

1.4 C++算法代码:

cpp 复制代码
class Solution {
public:
    void moveZeroes(vector<int>& nums) {
        for(int cur = 0,dest = -1; cur < nums.size(); cur++)
        {
            if(nums[cur] != 0)
            {
                dest++;
                swap(nums[cur],nums[dest]);
            }
        }
    }
};

1.5 算法总结:

这个方法是往后我们学习「快排算法」的时候,「数据划分」过程的重要一步。如果将快排算法拆解的话,这一段小代码就是实现快排算法的「核心步骤」。

1.6 手写笔记:


结尾:

往期精选:

《string 类模拟实现(上):从构造析构到插入操作的逐步实现》

《string 类模拟实现(下):补全核心功能,吃透字符串操作底层逻辑》

**结语:****本文围绕双指针算法展开,从理论形式到实际应用,以 "移动零" 问题为载体,完整呈现了算法设计与实现的全过程。文中不仅点明其与快排核心步骤的关联,帮助建立知识间的联系,还配套了题目链接与手写笔记,为自主练习提供便利。**如果这些内容对你理解双指针算法有帮助,不妨点个赞、收藏本文,也欢迎在评论区交流想法。后续还会分享更多算法实战解析,关注我的账号,一起稳步提升解题能力~

相关推荐
sali-tec5 小时前
C# 基于halcon的视觉工作流-章49-网面破损
开发语言·图像处理·算法·计算机视觉·c#
AlexMercer10125 小时前
Ubuntu从零开始配置Git
c++·git·ubuntu·gitee
ysa0510305 小时前
Fenwick 树进行快速统计
算法
im_AMBER6 小时前
Leetcode 33
算法·leetcode·职场和发展
andyguo6 小时前
全面解读大型语言模型测评:从认知演进到实操框架
人工智能·算法
lzptouch6 小时前
线性回归算法
算法·回归·线性回归
无敌最俊朗@6 小时前
C++ STL Deque 高频面试题与答案
开发语言·c++
和编程干到底7 小时前
C++基础
开发语言·c++
曹牧7 小时前
C#:数组不能使用Const修饰符
java·数据结构·算法