LeetCode 283 移动零

点此看全部题解 LeetCode必刷100题:一份来自面试官的算法地图(题解持续更新中)

生活中的算法

你有没有整理过房间?常常会发现一些要丢掉的东西,但又不想立刻处理。这时候,我们通常会先把这些东西推到角落,把有用的东西集中在一起。等整理完后,再统一处理角落里的那些要丢弃的物品。

这就很像我们今天要讲的"移动零"问题:把数组中的零移到末尾,同时保持其他元素的相对顺序不变。就像整理房间时,我们把不要的东西(零)移到角落,同时保持其他物品(非零元素)的摆放顺序不变。

问题描述

LeetCode第283题"移动零"是这样描述的:给定一个数组nums,编写一个函数将所有0移动到数组的末尾,同时保持非零元素的相对顺序。要求必须在原数组上操作,不能使用额外的数组空间。

比如,输入:nums = [0,1,0,3,12],处理后应该得到:[1,3,12,0,0]。

最直观的解法:两次遍历法

最容易想到的方法就是:先把所有非零元素按顺序排在数组前面,然后把剩下的位置都填上0。就像整理房间时,先把要留下的东西整理好,然后剩下的空间就是要清理的区域。

具体步骤是这样的:

  1. 用一个指针记录当前应该放置非零元素的位置
  2. 遍历数组,遇到非零元素就放到这个位置,并移动指针
  3. 最后,从指针位置到数组末尾都填充0

让我们用一个例子来模拟这个过程:

  1. 原数组:[0,1,0,3,12]
  2. 第一次遍历(移动非零元素):
  3. pos = 0, 遇到0,跳过
  4. pos = 0, 遇到1,放入pos位置:[1,1,0,3,12],pos++
  5. pos = 1, 遇到0,跳过
  6. pos = 1, 遇到3,放入pos位置:[1,3,0,3,12],pos++
  7. pos = 2, 遇到12,放入pos位置:[1,3,12,3,12],pos++
  8. 第二次遍历(填充0):
  9. pos=3开始填充0:[1,3,12,0,0]

这种思路可以用Java代码这样实现:

  1. public void moveZeroes(int[] nums) {
  2. // 记录非零元素应该放置的位置
  3. int pos = 0;
  4. // 第一次遍历:放置非零元素
  5. for (int num : nums) {
  6. if (num != 0) {
  7. nums[pos] = num;
  8. pos++;
  9. }
  10. }
  11. // 第二次遍历:填充0
  12. while (pos < nums.length) {
  13. nums[pos] = 0;
  14. pos++;
  15. }
  16. }

优化解法:单次遍历法

仔细观察可以发现,我们其实可以用一次遍历就完成任务。关键是用两个指针:一个指向当前应该放置非零元素的位置,另一个用来遍历数组。当遇到非零元素时,把它和前面的零交换位置。

单次遍历法的原理

  1. 用左指针记录下一个非零元素应该放置的位置
  2. 用右指针遍历数组
  3. 当右指针遇到非零元素时,将其与左指针指向的位置交换
  4. 左指针只有在处理非零元素时才移动

算法步骤(伪代码)

  1. 初始化左指针left = 0
  2. 遍历数组,右指针right从0到末尾:
    • 如果遇到非零元素
    • 交换left和right位置的元素
    • left指针右移
  3. 完成后,所有零都在数组末尾

示例运行

让我们用示例数组[0,1,0,3,12]模拟运行过程:

  1. 初始状态:[0,1,0,3,12],left=0right=0
  2. right=0
  3. - 遇到0,不操作
  4. right=1
  5. - 遇到1,与left交换:[1,0,0,3,12]
  6. - left移动到1
  7. right=2
  8. - 遇到0,不操作
  9. right=3
  10. - 遇到3,与left交换:[1,3,0,0,12]
  11. - left移动到2
  12. right=4
  13. - 遇到12,与left交换:[1,3,12,0,0]
  14. - left移动到3
  15. 结束

Java代码实现

  1. public void moveZeroes(int[] nums) {
  2. int left = 0; // 记录下一个非零元素应放置的位置
  3. // 遍历数组
  4. for (int right = 0; right < nums.length; right++) {
  5. if (nums[right] != 0) {
  6. // 如果left和right不同,才需要交换
  7. // 这个优化可以减少不必要的自身交换
  8. if (left != right) {
  9. // 交换left和right位置的元素
  10. int temp = nums[left];
  11. nums[left] = nums[right];
  12. nums[right] = temp;
  13. }
  14. left++;
  15. }
  16. }
  17. }

两次遍历vs单次遍历

让我们比较这两种解法:

两次遍历法的时间复杂度是O(n),需要遍历两次数组。它的优点是逻辑简单清晰,容易理解和实现。

单次遍历法的时间复杂度也是O(n),但只需要遍历一次数组。它通过巧妙的指针操作,一次遍历就完成了任务。虽然实现稍微复杂一些,但在实际运行时更高效。

两种方法的空间复杂度都是O(1),因为都是在原数组上进行操作。

题目模式总结

这道题体现了一个重要的数组操作模式:双指针技巧

这种技巧在数组操作中经常出现,比如:

  • 删除数组中的重复元素
  • 合并两个有序数组
  • 判断是否是回文数组

解决这类问题的通用思路是:

  1. 确定两个指针的用途(比如一个用于记录位置,一个用于遍历)
  2. 明确指针移动的条件
  3. 考虑元素交换或移动的时机

小结

通过这道题,我们不仅学会了如何高效地移动数组中的零元素,更重要的是掌握了双指针这一重要的编程技巧。这种技巧在处理数组问题时特别有用,能帮助我们写出更高效的代码。

记住,有时候看似简单的问题,通过巧妙的算法设计,能让解决方案变得更加优雅高效!


作者:忍者算法
公众号:忍者算法

从理房间到移动零:一道考察数组操作的经典题目|LeetCode 283 移动零的更多相关文章

  1. 前端与算法 leetcode 283. 移动零

    目录 # 前端与算法 leetcode 283. 移动零 题目描述 概要 提示 解析 解法一:暴力法 解法二:双指针法 算法 传入[0,1,0,3,12]的运行结果 执行结果 GitHub仓库 # 前 ...

  2. Leetcode 283.移动零

    移动零 给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序. 示例: 输入: [0,1,0,3,12] 输出: [1,3,12,0,0] 说明: 必须在原数组 ...

  3. Java实现 LeetCode 283 移动零

    283. 移动零 给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序. 示例: 输入: [0,1,0,3,12] 输出: [1,3,12,0,0] 说明: 必 ...

  4. 一道javascript数组操作题

    题目如下: var arr = ['100px','abc'-6,[],-98765,34,-2,0,'300',,function(){alert(1);}, null, document, [], ...

  5. python(leetcode)-283移动零

    给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序. 示例: 输入: [0,1,0,3,12] 输出: [1,3,12,0,0] 说明: 必须在原数组上操作, ...

  6. Leetcode 283.移动零 By Python

    思路 我们可以用python的list comprehension来取出所以非0的元素,而且这样取出来会保持原有的相对顺序,再统计先后变化的长度,补上相应的0即可 代码 class Solution( ...

  7. 【Leetcode】【简单】【283. 移动零】【JavaScript】

    题目描述 283. 移动零 给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序. 示例: 输入: [0,1,0,3,12]输出: [1,3,12,0,0] 说 ...

  8. 【LeetCode】283.移动零

    283.移动零 知识点:数组:双指针: 题目描述 给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序. 示例 输入: [0,1,0,3,12] 输出: [1, ...

  9. golang学习笔记20 一道考察对并发多协程操作一个共享变量的面试题

    golang学习笔记20 一道考察对并发多协程操作一个共享变量的面试题 下面这个程序运行的能num结果是什么? package main import ( "fmt" " ...

  10. Effective Java 之-----返回零长度的数组或集合而不是null

    如下代码,通常用户列表为空时,会习惯性返回null,因为这时会认为:null返回值比零长度数组更好,因为它避免了分配数组所需要的开销. private final List<UserBean&g ...

随机推荐

  1. Redis中有事务吗?有何不同?

    与关系型数据库事务的区别 Redis事务是指将多条命令加入队列,一次批量执行多条命令,每条命令会按顺序执行,事务执行过程中不会被其他客户端发来的命令所打断.也就是说,Redis事务就是一次性.顺序性. ...

  2. after_request 可以直接用于接口日志

  3. Vue.js axios

    1.安装与引入 Axios 是一个基于 promise 的 HTTP 库,可以用在浏览器和 node.js 中,官方文档 在HTML文件中引入 <script src="https:/ ...

  4. 使用 cProfile 分析和定位 Python 应用性能瓶颈点

    一.需求背景 性能压测时,发现某接口存在性能瓶颈,期望借助工具定位该瓶颈,最好能定位至具体慢方法. 二.cProfile 简介 cProfile 是 Python 标准库中的一个模块,用于对 Pyth ...

  5. 智能存储 | 超质感 HDR 生产,激活你的视神经

    视频平台尊贵的会员可以享受 4K HDR 超清视界,各类新型旗舰机都具备拍摄 HDR 视频的能力,3C 产品发布会必提 HDR 超清显示.想必各位看官感受到视觉逐渐被 HDR 浪潮侵袭了,那 HDR ...

  6. 2024年1月Java项目开发指南7:增删改查与接口测试

    我们之前,是从Controller层写到Service层,然后mapper层. 接下来我们反过来,从mapper层写到Controller层 两种方式都可以,你喜欢就行,甚至你先写service层也可 ...

  7. 解决编译redis报错zmalloc.h:50:10: fatal error: jemalloc/jemalloc.h: No such file or directory

    编译redis时报错:zmalloc.h:50:10: fatal error: jemalloc/jemalloc.h: No such file or directory,执行: # sudo m ...

  8. FFmpeg中的色彩空间与像素格式2-RGB/YUV色彩空间

    cnblogs 网站将文本J:a:b渲染成了J️b.是否可通过设置博客后台解决此问题?有知道的同学请留言指点一下,谢谢. FFmpeg 中的色彩与像素系列文章如下: [1]. FFmpeg中的色彩空间 ...

  9. Error: Assertion failed (nimages > 0) in cv::calibrateCameraRO, file D:\opencv4\opencv\opencv-4.1.0\modules\calib3d\src\calibration.cpp, line 3691

    报错信息: Error: Assertion failed (nimages > 0) in cv::calibrateCameraRO, file D:\opencv4\opencv\open ...

  10. 安装OpenCV时提示缺少boostdesc_bgm.i文件的问题解决方案

    安装OpenCV时,会遇到下面的错误 /home/zhang/slam/opencv-3.4.5/opencv_contrib/modules/xfeatures2d/src/boostdesc.cp ...