从理房间到移动零:一道考察数组操作的经典题目|LeetCode 283 移动零
LeetCode 283 移动零
点此看全部题解 LeetCode必刷100题:一份来自面试官的算法地图(题解持续更新中)
生活中的算法
你有没有整理过房间?常常会发现一些要丢掉的东西,但又不想立刻处理。这时候,我们通常会先把这些东西推到角落,把有用的东西集中在一起。等整理完后,再统一处理角落里的那些要丢弃的物品。
这就很像我们今天要讲的"移动零"问题:把数组中的零移到末尾,同时保持其他元素的相对顺序不变。就像整理房间时,我们把不要的东西(零)移到角落,同时保持其他物品(非零元素)的摆放顺序不变。
问题描述
LeetCode第283题"移动零"是这样描述的:给定一个数组nums,编写一个函数将所有0移动到数组的末尾,同时保持非零元素的相对顺序。要求必须在原数组上操作,不能使用额外的数组空间。
比如,输入:nums = [0,1,0,3,12],处理后应该得到:[1,3,12,0,0]。
最直观的解法:两次遍历法
最容易想到的方法就是:先把所有非零元素按顺序排在数组前面,然后把剩下的位置都填上0。就像整理房间时,先把要留下的东西整理好,然后剩下的空间就是要清理的区域。
具体步骤是这样的:
- 用一个指针记录当前应该放置非零元素的位置
- 遍历数组,遇到非零元素就放到这个位置,并移动指针
- 最后,从指针位置到数组末尾都填充0
让我们用一个例子来模拟这个过程:
原数组:[0,1,0,3,12]
第一次遍历(移动非零元素):
pos = 0, 遇到0,跳过
pos = 0, 遇到1,放入pos位置:[1,1,0,3,12],pos++
pos = 1, 遇到0,跳过
pos = 1, 遇到3,放入pos位置:[1,3,0,3,12],pos++
pos = 2, 遇到12,放入pos位置:[1,3,12,3,12],pos++
第二次遍历(填充0):
从pos=3开始填充0:[1,3,12,0,0]
这种思路可以用Java代码这样实现:
public void moveZeroes(int[] nums) {
// 记录非零元素应该放置的位置
int pos = 0;
// 第一次遍历:放置非零元素
for (int num : nums) {
if (num != 0) {
nums[pos] = num;
pos++;
}
}
// 第二次遍历:填充0
while (pos < nums.length) {
nums[pos] = 0;
pos++;
}
}
优化解法:单次遍历法
仔细观察可以发现,我们其实可以用一次遍历就完成任务。关键是用两个指针:一个指向当前应该放置非零元素的位置,另一个用来遍历数组。当遇到非零元素时,把它和前面的零交换位置。
单次遍历法的原理
- 用左指针记录下一个非零元素应该放置的位置
- 用右指针遍历数组
- 当右指针遇到非零元素时,将其与左指针指向的位置交换
- 左指针只有在处理非零元素时才移动
算法步骤(伪代码)
- 初始化左指针left = 0
- 遍历数组,右指针right从0到末尾:
- 如果遇到非零元素
- 交换left和right位置的元素
- left指针右移
- 完成后,所有零都在数组末尾
示例运行
让我们用示例数组[0,1,0,3,12]模拟运行过程:
初始状态:[0,1,0,3,12],left=0,right=0
right=0:
- 遇到0,不操作
right=1:
- 遇到1,与left交换:[1,0,0,3,12]
- left移动到1
right=2:
- 遇到0,不操作
right=3:
- 遇到3,与left交换:[1,3,0,0,12]
- left移动到2
right=4:
- 遇到12,与left交换:[1,3,12,0,0]
- left移动到3
结束
Java代码实现
public void moveZeroes(int[] nums) {
int left = 0; // 记录下一个非零元素应放置的位置
// 遍历数组
for (int right = 0; right < nums.length; right++) {
if (nums[right] != 0) {
// 如果left和right不同,才需要交换
// 这个优化可以减少不必要的自身交换
if (left != right) {
// 交换left和right位置的元素
int temp = nums[left];
nums[left] = nums[right];
nums[right] = temp;
}
left++;
}
}
}
两次遍历vs单次遍历
让我们比较这两种解法:
两次遍历法的时间复杂度是O(n),需要遍历两次数组。它的优点是逻辑简单清晰,容易理解和实现。
单次遍历法的时间复杂度也是O(n),但只需要遍历一次数组。它通过巧妙的指针操作,一次遍历就完成了任务。虽然实现稍微复杂一些,但在实际运行时更高效。
两种方法的空间复杂度都是O(1),因为都是在原数组上进行操作。
题目模式总结
这道题体现了一个重要的数组操作模式:双指针技巧。
这种技巧在数组操作中经常出现,比如:
- 删除数组中的重复元素
- 合并两个有序数组
- 判断是否是回文数组
解决这类问题的通用思路是:
- 确定两个指针的用途(比如一个用于记录位置,一个用于遍历)
- 明确指针移动的条件
- 考虑元素交换或移动的时机
小结
通过这道题,我们不仅学会了如何高效地移动数组中的零元素,更重要的是掌握了双指针这一重要的编程技巧。这种技巧在处理数组问题时特别有用,能帮助我们写出更高效的代码。
记住,有时候看似简单的问题,通过巧妙的算法设计,能让解决方案变得更加优雅高效!
作者:忍者算法
公众号:忍者算法
从理房间到移动零:一道考察数组操作的经典题目|LeetCode 283 移动零的更多相关文章
- 前端与算法 leetcode 283. 移动零
目录 # 前端与算法 leetcode 283. 移动零 题目描述 概要 提示 解析 解法一:暴力法 解法二:双指针法 算法 传入[0,1,0,3,12]的运行结果 执行结果 GitHub仓库 # 前 ...
- Leetcode 283.移动零
移动零 给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序. 示例: 输入: [0,1,0,3,12] 输出: [1,3,12,0,0] 说明: 必须在原数组 ...
- Java实现 LeetCode 283 移动零
283. 移动零 给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序. 示例: 输入: [0,1,0,3,12] 输出: [1,3,12,0,0] 说明: 必 ...
- 一道javascript数组操作题
题目如下: var arr = ['100px','abc'-6,[],-98765,34,-2,0,'300',,function(){alert(1);}, null, document, [], ...
- python(leetcode)-283移动零
给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序. 示例: 输入: [0,1,0,3,12] 输出: [1,3,12,0,0] 说明: 必须在原数组上操作, ...
- Leetcode 283.移动零 By Python
思路 我们可以用python的list comprehension来取出所以非0的元素,而且这样取出来会保持原有的相对顺序,再统计先后变化的长度,补上相应的0即可 代码 class Solution( ...
- 【Leetcode】【简单】【283. 移动零】【JavaScript】
题目描述 283. 移动零 给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序. 示例: 输入: [0,1,0,3,12]输出: [1,3,12,0,0] 说 ...
- 【LeetCode】283.移动零
283.移动零 知识点:数组:双指针: 题目描述 给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序. 示例 输入: [0,1,0,3,12] 输出: [1, ...
- golang学习笔记20 一道考察对并发多协程操作一个共享变量的面试题
golang学习笔记20 一道考察对并发多协程操作一个共享变量的面试题 下面这个程序运行的能num结果是什么? package main import ( "fmt" " ...
- Effective Java 之-----返回零长度的数组或集合而不是null
如下代码,通常用户列表为空时,会习惯性返回null,因为这时会认为:null返回值比零长度数组更好,因为它避免了分配数组所需要的开销. private final List<UserBean&g ...
随机推荐
- CommonsBeanUtils1(基于ysoserial)
环境准备 JDK1.8(8u421) JDK8的版本应该都没什么影响,这里直接以我的镜像为准了.commons-beanutils:commons-beanutils:1.9.2.commons-co ...
- ThreeJs-03材质进阶
一.uv贴图 在3D计算机图形学中,UV映射是一种将2D纹理映射到3D模型表面的方法.在这里,"U"和"V"代表了2D纹理空间的坐标,这与2D笛卡尔坐标系统中的 ...
- MySQL之查询操作
1)使用in查询, 保持顺序 SELECT * FROM `template_data` where template_id in (7339747298123169843,7339747324194 ...
- 开发工具之DevToys
DevToys 号称开发人员的瑞士军刀,可以帮助完成一些日常任务,比如格式化 JSON.比较文本.测试正则等,无需使用许多不真实的网站来处理的数据. 借助智能检测,DevToys 能够检测出可以处理在 ...
- Educational Codeforces Round 132 (Rated for Div
Educational Codeforces Round 132 (Rated for Div. 2) Recover an RBS 给你一个括号序列,里面存在?号,题目保证至少有一种方案使得该括号序 ...
- uni-app下载文件在ios下失败
标签: js uni-app 前情 uni-app是我很喜欢的跨平台框架,它能开发小程序,H5,APP(安卓/iOS),对前端开发很友好,自带的IDE让开发体验也很棒,公司项目就是主推uni-app. ...
- k8s pod错误的排查步骤和处理方法
查pod kubectl get pod -n amadeus -o wide 查pod日志 kubectl logs -f --timestamps -n amadeus weyo-server-6 ...
- 用 erlang 描述 tcc
Transaction 视为一个 Actor. start_transaction(Order) -> p1 = spawn(start_order(self, Order.subOrder1) ...
- 【Python】【Pandas】将符合条件行的某列数值改为负数
萌狼蓝天情景还原: 支付宝/微信导出的账单,不管支出还是收入都是正数. 我想把支出的金额改成负数,其他不变就这样. 解决办法 这里用到的是pandas.apply e--下面的写法虽然比较麻烦,但是 ...
- Qt/C++入门基础学习001-绘图基础
这一节介绍 Qt 的绘图基础知识,我们都知道,Qt 里绘图使用的是 QPainter,但是首先需要弄明白:在什么上绘图和在哪里绘图,然后才是怎么绘图,我们就围绕这几个问题来展开. 在什么上绘图 The ...