【算法专题--双指针算法】leetcode--283. 移动零、leetcode--1089. 复写零

这篇具有很好参考价值的文章主要介绍了【算法专题--双指针算法】leetcode--283. 移动零、leetcode--1089. 复写零。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。


【算法专题--双指针算法】leetcode--283. 移动零、leetcode--1089. 复写零,算法,leetcode,c++,数据结构,推荐算法
🍁你好,我是 RO-BERRY
📗 致力于C、C++、数据结构、TCP/IP、数据库等等一系列知识
🎄感谢你的陪伴与支持 ,故事既有了开头,就要画上一个完美的句号,让我们一起加油

【算法专题--双指针算法】leetcode--283. 移动零、leetcode--1089. 复写零,算法,leetcode,c++,数据结构,推荐算法



前言

双指针
常见的双指针有两种形式,一种是对撞指针,⼀种是左右指针。
对撞指针:一般用于顺序结构中,也称左右指针。

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

快慢指针:又称为龟兔赛跑算法,其基本思想就是使用两个移动速度不同的指针在数组或链表等序列
结构上移动。
这种方法对于处理环形链表或数组非常有用。
其实不单单是环形链表或者是数组,如果我们要研究的问题出现循环往复的情况时,均可考虑使用快
慢指针的思想。

快慢指针的实现方式有很多种,最常用的⼀种就是:

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

1. 移动零(easy)

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

题目链接: 283. 移动零

题目描述:
给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。
请注意 ,必须在不复制数组的情况下原地对数组进行操作。
示例 1:

输入: nums = [0,1,0,3,12]
输出: [1,3,12,0,0]

示例 2:

输入: nums = [0]
输出: [0]

提示:

1 <= nums.length <= 104
-231 <= nums[i] <= 231 - 1
进阶:你能尽量减少完成的操作次数吗?


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

算法思路:

在本题中,我们可以用一个 cur 指针来扫描整个数组,另一个 dest 指针用来记录非零数序列的最后一个位置。根据 cur 在扫描的过程中,遇到的不同情况,分类处理,实现数组的划分。
在 cur 遍历期间,使 [0, dest] 的元素全部都是非零元素, [dest + 1, cur - 1] 的元素全是零。

算法流程:

  1. 初始化 cur = 0 (用来遍历数组), dest = -1 (指向非零元素序列的最后⼀个位置。
    因为刚开始我们不知道最后⼀个非零元素在什么位置,因此初始化为 -1 )
  2. cur 依次往后遍历每个元素,遍历到的元素会有下面两种情况:

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

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

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

【算法专题--双指针算法】leetcode--283. 移动零、leetcode--1089. 复写零,算法,leetcode,c++,数据结构,推荐算法

C++ 算法代码:

class Solution {
public:
    void moveZeroes(vector<int>& nums) {
        for(int des=-1,cur =0;cur<nums.size();cur++)
            if(nums[cur])
                swap(nums[++des],nums[cur]);
    }
};

C++ 代码结果:
【算法专题--双指针算法】leetcode--283. 移动零、leetcode--1089. 复写零,算法,leetcode,c++,数据结构,推荐算法

Java 算法代码:

class Solution
{
	public void moveZeroes(int[] nums)
	{
		for (int cur = 0, dest = -1; cur < nums.length; cur++)
			if (nums[cur] != 0) // 仅需处理⾮零元素
			{
				dest++; // dest 先向后移动⼀位
				// 交换
				int tmp = nums[cur];
				nums[cur] = nums[dest];
				nums[dest] = tmp;
			}
	}
}

3. 复写零(easy)

题目链接: 1089. 复写零
题目描述:

给你一个长度固定的整数数组 arr ,请你将该数组中出现的每个零都复写一遍,并将其余的元素向右平移。注意:请不要在超过该数组长度的位置写入元素。请对输入的数组 就地 进行上述修改,不要从函数返回任何东西。

示例 1:

输入:arr = [1,0,2,3,0,4,5,0]
输出:[1,0,0,2,3,0,0,4]
解释:调用函数后,输入的数组将被修改为:[1,0,0,2,3,0,0,4]

示例 2:

输入:arr = [1,2,3]
输出:[1,2,3]
解释:调用函数后,输入的数组将被修改为:[1,2,3]

提示:

1 <= arr.length <= 104
0 <= arr[i] <= 9

4.解法(原地复写 - 双指针)

确定目标位置:

  1. 首先,使用两个指针 dest 和 cur 来确定每个位置复制0后应该放置的位置。cur 指针用于遍历原始数组,而 dest 指针则用于确定在复制0后应该放置新元素的位置。cur 最终的位置就是复写后数组的最后一个数的位置。

如果 arr[cur] 不为0,那么 dest 只增加1,因为当前元素不需要复制。
如果 arr[cur] 为0,那么 dest 增加2,因为需要复制一个0放在当前0的后面。
处理边界情况:在遍历过程中,如果 dest 超过了数组的最大索引 n-1,则说明没有足够的空间来放置所有的0。在这种情况下,将数组的最后一个元素设置为0,并将 dest 和 cur 指针相应地向后移动。

  1. 从后向前复写:在确定了所有元素的目标位置后,从数组的末尾开始,根据原始数组中的元素值,将元素复制到它们的目标位置。

如果 arr[cur] 不为0,则将其复制到 arr[dest],并将两个指针都向前移动1位。
如果 arr[cur] 为0,则先复制一个0到 arr[dest],再复制另一个0到 arr[dest-1],然后将 cur 向前移动1位,dest 向前移动2位。

【算法专题--双指针算法】leetcode--283. 移动零、leetcode--1089. 复写零,算法,leetcode,c++,数据结构,推荐算法

解题方法

该算法使用双指针技术,通过一次遍历来确定每个元素的目标位置,然后从后向前进行复写。这种方法避免了额外的空间开销,并且只进行了一次遍历,因此效率较高。

时间复杂度: O(n),其中n是数组的长度。算法只进行了一次遍历,因此时间复杂度是线性的。
空间复杂度: O(1),算法只使用了常数个额外变量,没有使用与数组大小相关的额外空间。

总结

这个算法是一种高效的原地修改算法,它利用了双指针技术来避免额外的空间开销,并且只进行了一次遍历。这种算法的时间复杂度和空间复杂度都是最优的。

C++ 算法代码:

class Solution {
public:
    void duplicateZeros(vector<int>& arr) {
        //找最后一个数 
        int dest=-1,cur=0,n=arr.size();
        while(cur<n)
        {
            if(arr[cur])
                dest++;
            else
                dest+=2;
            if(dest>=n-1)
                break;
            cur++;
        }
        //边界情况
        if(dest>=n)
        {
            arr[n-1]=0;
            dest-=2;
            cur--;
        }
        while(cur>=0)
        {
            if(arr[cur])
                arr[dest--]=arr[cur--];
            else
            {
                arr[dest--]=arr[cur];
                arr[dest--]=arr[cur--];
            }

        }

    }
};

【算法专题--双指针算法】leetcode--283. 移动零、leetcode--1089. 复写零,算法,leetcode,c++,数据结构,推荐算法
Java 算法代码:文章来源地址https://www.toymoban.com/news/detail-840821.html

class Solution
{
	public void duplicateZeros(int[] arr)
	{
		int cur = 0, dest = -1, n = arr.length;
		// 1. 先找到最后⼀个需要复写的数
		while (cur < n)
		{
			if (arr[cur] == 0) dest += 2;
			else dest += 1;
			if (dest >= n - 1) break;
			cur++;
		}
		// 2. 处理⼀下边界情况
		if (dest == n)
		{
			arr[n - 1] = 0;
			cur--; dest -= 2;
		}
		// 3. 从后向前完成复写操作
		while (cur >= 0)
		{
			if (arr[cur] != 0) arr[dest--] = arr[cur--];
			else
			{
				arr[dest--] = 0;
				arr[dest--] = 0;
				cur--;
			}
		}
	}
}

到了这里,关于【算法专题--双指针算法】leetcode--283. 移动零、leetcode--1089. 复写零的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【优选算法】专题1 -- 双指针 -- 复写0

    前言: 补充一下前文没有写到的双指针入门知识:专题1 -- 双指针 -- 移动零 目录 基础入门知识: 1. 复写零(easy) 1. 题⽬链接:1089.复习0 - 力扣(LeetCode) 2. 题⽬描述: 3.算法原理: 异地操作 本地操作 【从后向前的复写过程】 整体思路: 🎯1.先找到最后一个“复写”的

    2024年04月17日
    浏览(33)
  • 【算法专题突破】双指针 - 复写零(2)

    目录 1. 题目解析 2. 算法原理 3. 代码编写 写在最后: 题目链接:1089. 复写零 - 力扣(Leetcode) 我先来读题, 题目的意思非常的简单,其实就是, 遇到 0 就复制一个写进数组,然后右边的元素就右移一位, 看一眼例子可以很容易理解题意。  一般像这种需要移动数组的元素

    2024年02月11日
    浏览(46)
  • 【算法挨揍日记】day01——双指针算法_移动零、 复写零

    283. 移动零 https://leetcode.cn/problems/move-zeroes/ 题目: 给定一个数组  nums ,编写一个函数将所有  0  移动到数组的末尾,同时保持非零元素的相对顺序。 请注意  ,必须在不复制数组的情况下原地对数组进行操作。    解题思路: 我们可以利用两个指针(dest和cur)的方法,

    2024年02月11日
    浏览(34)
  • 【算法专题突破】双指针 - 移动零(1)

    目录 写在前面 1. 题目解析 2. 算法原理 3. 代码编写 写在最后: 在进行了剑指Offer和LeetCode hot100的毒打之后, 我决心系统地学习一些经典算法,增强我的综合算法能力。 题目链接:283. 移动零 - 力扣(Leetcode) 读完题目大概就能明白他的意思, 就是在不改变其他数字的情况下

    2024年02月11日
    浏览(39)
  • 力扣:1089. 复写零

    今日分享一道力扣经典题目,复写0! 题目如下: 题目要求是进行复写0,而且不能超过原数组长度,且只能在原地进行操作! 解决本题最好的方法就是进行双指针方法! 一、双指针算法先 找到最后一个要复写的数 ! 二、然后 从后向前进行完成复写 (因为如果要是从前向

    2024年02月06日
    浏览(30)
  • LeetCode —— 复写零(双指针)

    力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台 将数组中出现的每个零复写一遍,然后将其他元素向右平移,数组长度不能改变。      

    2024年02月10日
    浏览(40)
  • Leetcode 283. 移动零

    题目链接 283. 移动零 给定一个数组 nums ,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。 请注意 ,必须在不复制数组的情况下原地对数组进行操作。 示例 1: 示例 2: 这道题目的意思是我们将所有的0都移动到数组的后面,非零的元素放在前面.不过我

    2024年02月08日
    浏览(64)
  • leetcode283. 移动零

    难度:简单题 题目 给定一个数组  nums ,编写一个函数将所有  0  移动到数组的末尾,同时保持非零元素的相对顺序。 请注意  ,必须在不复制数组的情况下原地对数组进行操作。 思路: 一开始想,从前往后遍历,遇到0就挪到最后。类似于冒泡的思想,但是这样做的话时

    2024年02月12日
    浏览(82)
  • LeetCode283.移动零

     这道题还是很简单的,我用的是双指针,左指针i从头开始遍历数组,右指针j是从i后面第一个数开始遍历,当左指针i等于0的时候,右指针j去寻找i右边第一个为0的数和i交换位置,交换完了就break内层循环,i往后移1位,j又从i的下一位开始,如果i不等于0,就不用进内层循环

    2024年02月12日
    浏览(43)
  • Leetcode 283.移动零

    给定一个数组  nums ,编写一个函数将所有  0  移动到数组的末尾,同时保持非零元素的相对顺序。 请注意  ,必须在不复制数组的情况下原地对数组进行操作。 示例 1: 示例 2: 提示 : 1 = nums.length = 104 -231 = nums[i] = 231 - 1 进阶: 你能尽量减少完成的操作次数吗? 直接采用快

    2024年02月22日
    浏览(40)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包