LeetCode 算法入门 — 移动零
2024-01-27 21:00:49
移动零:算法入门指南
踏入算法的世界,移动零 算法将作为你初学者之旅的垫脚石。看似简单,它却蕴含着算法思维的精髓,是算法入门必备的经典题型。
算法解析
原地操作法
想象一下你在操场玩耍,你的朋友都跑走了,只留下你一个人。为了重新加入游戏,你需要移动到一个非空的位置。同样的概念适用于移动零算法。
使用两个指针,一个指向当前元素,另一个指向非零元素的下一个位置。如果当前元素不为零,就像你是一个非零元素,那么你就和你的朋友(下一个非零元素)交换位置,然后你的朋友往前移动一步。如果当前元素为零,就像你是一个空位置,那么你往前移动一步,让非零元素填补你的位置。就这样,通过不断地交换和移动,所有的非零元素都聚集在数组的前面,而零元素被移动到数组的后面。
新建数组法
另一种方法是建立一个新的操场(数组),只邀请非零元素加入。遍历原操场,将所有非零元素带到新操场。然后,你只需销毁旧操场,将新操场作为你唯一的游乐场。
代码示例
def move_zeros(nums):
"""
原地操作法移动零。
参数:
nums: 待移动零的列表。
返回:
无。
"""
i = 0
j = 0
while i < len(nums):
if nums[i] != 0:
nums[i], nums[j] = nums[j], nums[i]
j += 1
i += 1
def move_zeros2(nums):
"""
新建数组法移动零。
参数:
nums: 待移动零的列表。
返回:
无。
"""
new_nums = []
for num in nums:
if num != 0:
new_nums.append(num)
nums[:] = new_nums
实例
考虑数组 [0, 1, 0, 3, 12]。
原地操作法:
当前位置 | 非零位置 | 交换 | 移动 | 数组 |
---|---|---|---|---|
0 | 1 | 交换 | [1, 0, 0, 3, 12] | |
1 | 2 | 前移 | [1, 0, 0, 3, 12] | |
2 | 3 | 前移 | [1, 0, 0, 3, 12] | |
3 | 4 | 交换 | [1, 3, 0, 0, 12] | |
4 | 5 | 前移 | [1, 3, 0, 0, 12] |
新建数组法:
非零元素 | 新数组 |
---|---|
1 | [1] |
3 | [1, 3] |
12 | [1, 3, 12] |
因此,最终数组为 [1, 3, 12, 0, 0]。
总结
移动零算法是算法入门旅程中一颗璀璨的宝石。它不仅教导了你算法思维,还为你的算法宝库增添了一项基本技能。当你踏上算法之旅时,记住这颗宝石,并用它来解锁算法世界中更多的奥秘。
常见问题解答
-
原地操作法和新建数组法哪个更好?
两种方法各有优缺点。原地操作法效率更高,因为它只需要一次遍历。新建数组法更简单,因为它不需要复杂的指针操作。
-
移动零算法是否适用于负数?
是的,移动零算法适用于负数和零。它会将所有非零元素移动到数组的前面,无论它们是正数还是负数。
-
移动零算法的时间复杂度是多少?
原地操作法和新建数组法的最坏情况时间复杂度均为 O(n),其中 n 是数组的长度。
-
移动零算法的空间复杂度是多少?
原地操作法的空间复杂度为 O(1),因为它不需要额外的空间。新建数组法的空间复杂度为 O(n),因为它需要一个新数组来存储非零元素。
-
移动零算法是否适用于链表?
移动零算法可以应用于链表,但需要一些修改。链表中的指针操作略有不同,你需要遍历整个链表以找到非零元素。