当前位置: 首页 > news >正文

算法每日双题精讲——双指针(移动零,复写零)

🌟快来参与讨论💬,点赞👍、收藏⭐、分享📤,共创活力社区。 🌟

别再犹豫了!快来订阅我们的算法每日双题精讲专栏,一起踏上算法学习的精彩之旅吧!💪


💯前言

在算法的世界里,双指针技巧常常能发挥出神奇的作用😎。今天,我们就来精讲两道利用双指针解决的经典题目:移动零和复写零。 

📣由于俩道题目均为数组,这里的双指针算法指的是:利用数组下标代替指针

当我们遇到,数组分块,数组划分的问题时,可以考虑使用双指针法。 

 


 💯双指针的作用

✍两个指针的作用:

  • cur:从左往右扫描数组,遍历数组
  • dest:已处理的区间内,非零元素的最后一个位置

分为三个区间:

  1. [0, dest]
  2. [dest + 1,cur -1]
  3. [cur, n -1]

💯移动零

题目链接👉【力扣】 

题目描述:给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。

示例:
输入:nums = {0,1,0,3,12}
输出:{1,3,12,0,0}

⭐解题思路:

我们可以使用双指针法来解决这个问题。一个指针 cur用于遍历整个数组,另一个指针dest 用于指向当前非零元素应该放置的位置。当遇到非零元素时,将其放置在dest 指针所指的位置,并将dest 指针向后移动一位。遍历结束后,从dest 指针开始到数组末尾的位置全部设置为零。

 😀俩个指针将数组分为三个区间:

  1. [0, dest]:全是非0的元素(已经处理)
  2. [dest + 1,cur -1]:都是0(已经处理)
  3. [cur, n -1]:还未处理过的

 

 代码实现(以 C++ 为例):
class Solution {
public:void moveZeroes(vector<int>& nums) {// dest 用于标记已处理的非零元素的最后位置int dest = -1;// cur 用于遍历整个向量int cur = 0;while (cur < nums.size()) {// 如果当前位置的元素为 0if (nums[cur] == 0) {cur++;} else {// 先将 dest 加 1,标记下一个非零元素应放置的位置swap(nums[++dest], nums[cur]);cur++;}}}
};
👀复杂度分析:
  • 时间复杂度:O(n),其中 n 是数组的长度。我们只需要遍历一次数组。
  • 空间复杂度:O(1),只使用了有限的额外空间。

💯复写零

题目链接👉【力扣】

题目描述:给你一个长度固定的整数数组 arr,请你将该数组中出现的每个零都复写一遍,并将其余的元素向右平移。注意❗:不要在超过该数组长度的位置写入元素。

示例:
输入:arr = {1,0,2,3,0,4,5,0}
输出:{1,0,0,2,3,0,0,4}

 

解题思路:

同样可以使用双指针法来解决这个问题。一个指针cur用于遍历数组,另一个指针dest用于指向复写零后数组中元素应该放置的位置。当遇到零元素时,将dest指针后的元素依次向后移动两位,并在dest和 dest+1 的位置都放置零。当遇到非零元素时,将其放置在dest指针所指的位置,并将dest指针向后移动一位。

🙋这个解题思路是怎么来的呢? 
  1. 首先我们从左往右遍历数组, 

     

    当arr[cur]!=0时,我们让dest的后面一个的值赋予a[cur]正指向的那个值

    当arr[cur]==0时,我们让dest的后俩个值都赋予0

    当走到这一步时:


    cur找不到下一个为2的值了,因此我们不能从左往右遍
  2. 我们从右往左遍历,dset指向最后一个元素,cur指向最后一个要复写的数
    当a[cur]!=0时,让a[dest]=a[cur],然后cur--,dest--;
    当a[cur]==0时,让a[dest--]=0,a[dest--]=0,cur--;
    这样遍历没有问题,因此我们选择从右往左遍历
    所以我们只要找到最后要“复写”的数即可

⭐找最后一个要复写的数 

 

👇起初让cur指向数组的开头,dest指向-1的位置: 

代码实现(以 C++ 为例): 
class Solution {
public:void duplicateZeros(vector<int>& arr) {// dest 用于标记复制零元素后的新位置,初始值为 -1int dest = -1;// cur 用于遍历原始数组,初始值为 0int cur = 0;int n = arr.size();// 遍历原始数组,确定复制零元素后的新位置while (cur < n) {// 如果当前元素不为 0if (arr[cur]!= 0) {// dest 向后移动一位dest++;} else {// 如果当前元素为 0,dest 向后移动两位(因为要复制一个零)dest += 2;}// 如果 dest 已经到达或超过新数组的最后一个位置,跳出循环if (dest >= n - 1) break;// cur 向后移动一位,继续遍历原始数组cur++;}// 如果 dest 正好等于新数组的长度if (dest == n) {// 将新数组的最后一个位置设为 0arr[n - 1] = 0;// dest 回退两位dest -= 2;// cur 回退一位,因为上一步 cur 多走了一步cur--;}// 从后往前遍历原始数组,进行复制操作while (cur >= 0) {// 如果当前元素不为 0if (arr[cur]!= 0) {// 将当前元素复制到新位置arr[dest] = arr[cur];// cur 和 dest 都向前移动一位cur--;dest--;} else {// 如果当前元素为 0,先将 0 复制到 dest 位置,再将另一个 0 复制到 dest - 1 位置arr[dest--] = 0;arr[dest--] = 0;// cur 向前移动一位cur--;}}}
};
👀复杂度分析:
  • 时间复杂度:O(n),其中 n 是数组的长度。我们需要遍历两次数组。
  • 空间复杂度:O(1),只使用了有限的额外空间。

💯总结

通过这两道题目,我们可以看到双指针算法在处理数组相关问题时的高效性和灵活性👏。希望大家在今后的算法学习中,能够熟练掌握双指针技巧,解决更多复杂的问题💪。


我以后还会对 算法 相关知识进行更多的创作,欢迎大家关注我,一起探索 算法 的奇妙世界😜

👉【A Charmer】

 


http://www.mrgr.cn/news/67741.html

相关文章:

  • JAVA 应用实现 APM 自动注入(主机篇)
  • Mysql基础 01 数据与sql
  • 数据转换 | Matlab基于SP符号递归图(Symbolic recurrence plots)一维数据转二维图像方法
  • 【022A】基于51单片机音乐盒
  • 雷池社区版 7.1.0 LTS 发布了
  • 【数据结构】算法的时间复杂度和空间复杂度
  • 2024年1-9月江苏省产业转移分析报告
  • 海外便宜云服务器盘点,10个热门服务器商家推荐
  • 29.6 时序统计的结构体对象和metrics结果打点方法
  • 禅道与Jira与Ones对比:哪个更适合你的项目管理需求?
  • 在数据库设计中,如何避免全表扫描?
  • 项目:使用LNMP搭建私有云存储
  • C语言复习第7章 自定义类型(结构体+位段+枚举+联合体)
  • 还有人不会设置微信自动回复?
  • YOLOv8相较于YOLOv5有哪些改进?
  • ubuntu【桌面】 配置NAT模式固定IP
  • 【NLP自然语言处理】深入解析Encoder与Decoder模块:结构、作用与深度学习应用
  • faiss里面SQ量化4bit是啥意思?具体举例并解释
  • 符号回归概念
  • 黑马redis原理篇 数据结构 set
  • [蓝桥杯算法从小白到大牛]动态规划第二讲:三步问题
  • 如何使用 C# 编写一个修改文件时间属性的小工具?
  • Java 实训 十四天 IO流
  • 对称二叉树(力扣101)
  • 国标GB28181
  • 一台电脑如何同时多开多 IP 浏览器多登账号?