返回

零的位移:解析 LeetCode 283 号问题

前端

引言

在 LeetCode 浩瀚的题目海洋中,283 号问题「移动零」以其简洁的和深邃的算法内核,吸引着众多程序员的探索。本文将以独树一帜的视角,带领读者领略这道题目的魅力,并深入剖析其背后的算法策略。

问题的提出

给定一个整数数组 nums,要求编写一个函数,将所有 0 元素移动到数组末尾,同时保持非零元素的相对顺序不变。

剖析与解答

思路一:原地交换

一种直观的想法是,逐个遍历数组,将非零元素与 0 元素进行原地交换,直到所有非零元素都被移动到数组头部。该方法的伪代码如下:

for i = 0 to n - 1:
    if nums[i] != 0:
        swap(nums[i], nums[j])
        j++

思路二:双指针

另一种更优雅的解法,引入了双指针的概念。慢指针 i 负责追踪当前非零元素的位置,快指针 j 负责遍历整个数组。当 j 指向一个非零元素时,将其与 i 指向的元素交换,并更新 i 的位置。该方法的伪代码如下:

i = 0
for j = 0 to n - 1:
    if nums[j] != 0:
        swap(nums[i], nums[j])
        i++

代码示例

以下以 C++ 语言为例,演示了双指针解法的实现:

class Solution {
public:
    void moveZeroes(vector<int>& nums) {
        int n = nums.size();
        int i = 0, j = 0;
        while (j < n) {
            if (nums[j] != 0) {
                swap(nums[i], nums[j]);
                i++;
            }
            j++;
        }
    }
};

性能分析

两种解法的时间复杂度均为 O(n),其中 n 为数组 nums 的长度。原地交换方法的空间复杂度为 O(1),而双指针方法则需要额外的空间来存储 ij 指针,因此其空间复杂度为 O(1)。

延伸与思考

  • 子数组移动零: LeetCode 上还有另一道变体题,要求移动指定子数组内的所有 0 元素。该问题可以利用双指针的思想进行求解。
  • 其他算法策略: 除了上述两种方法外,还可以使用哈希表或位运算等其他算法策略来解决该问题。
  • 算法优化: 当数组中包含大量 0 元素时,可以考虑使用快速排序或其他优化算法来提高效率。

结语

LeetCode 283 号问题「移动零」看似简单,却蕴含着算法设计和性能优化的深刻哲理。通过剖析不同的解法,我们可以拓展算法思维,提升代码效率。希望这篇文章能为读者提供全新的视角,激发更多编程灵感。