返回
复写零:从简单到深刻的算法思维
后端
2023-11-17 22:56:19
复写零:表面上的简单
LeetCode 1089 问题如下:
给定一个数组 nums
,其中每个元素都是正整数,请将所有 0 移到数组的末尾,同时保持非零元素的相对顺序。
例如:
输入:nums = [1,0,2,0,3,0,4,5]
输出:[1,2,3,4,5,0,0,0]
乍一看,这是一个非常简单的题目。我们可以使用一个简单的循环,逐个检查数组中的每个元素,并将非零元素移动到数组的前面,同时将零元素移动到数组的末尾。然而,这种朴素算法的时间复杂度为 O(n^2),其中 n 是数组的长度。对于大型数组,这种算法的效率会非常低。
优化算法:从朴素到高效
为了提高算法的效率,我们可以使用双指针法。我们使用两个指针 i
和 j
,其中 i
指向非零元素,j
指向零元素。然后,我们执行以下步骤:
- 如果
nums[i]
非零,则将nums[i]
与nums[j]
交换,然后将i
和j
都向右移动一步。 - 如果
nums[i]
为零,则仅将j
向右移动一步。
通过这种方法,我们只遍历数组一遍,时间复杂度降为 O(n)。
def duplicateZeros(nums):
i, j = 0, 0
while j < len(nums):
if nums[i] != 0:
nums[j] = nums[i]
j += 1
i += 1
if i < len(nums) and nums[i] == 0:
j += 1
if j < len(nums):
nums[j] = 0
数论的妙用:一次性解决问题
除了双指针法,我们还可以使用数论来一次性解决这个问题。我们可以利用数组 nums
中非零元素的个数 cnt
。然后,我们从后往前遍历数组,对于每个非零元素 nums[i]
, 将 nums[cnt + i]
设置为 nums[i]
。最后,将剩余的元素全部设置为 0。
def duplicateZeros(nums):
cnt = 0
for num in nums:
if num != 0:
cnt += 1
i = cnt - 1
j = len(nums) - 1
while i >= 0:
if nums[i] != 0:
nums[j] = nums[i]
j -= 1
if i > 0 and nums[i] == 0:
nums[j] = 0
j -= 1
i -= 1
结语
复写零问题看似简单,但它展示了从朴素算法到优化算法,再到数论应用的算法思维进化过程。通过剖析不同算法的优缺点,我们加深了对算法思维的理解,也提高了解决实际问题的效率。持续探索算法的奥秘,解锁更广阔的编程世界。