【移动零】

移动零

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

请注意 ,必须在不复制数组的情况下原地对数组进行操作。

示例 1:

输入: nums = [0,1,0,3,12]
输出: [1,3,12,0,0]

示例 2:

输入: nums = [0]
输出: [0]

提示:

1 <= nums.length <= 104
-231 <= nums[i] <= 231 - 1

进阶:你能尽量减少完成的操作次数吗?

作者:LeetCode
链接:https://leetcode.cn/leetbook/read/all-about-array/x9rh8e/
来源:力扣(LeetCode)

class Solution {
public:
    void moveZeroes(vector<int>& nums) {
        int i = 0, j = 0;
        // 遍历整个数组,将所有非零元素都移动到数组的前面
        while (j < nums.size()) {
            if (nums[j] != 0) {
                nums[i] = nums[j];
                i++;
            }
            j++;
        }
        // 将剩余的位置都填充为 0
        while (i < nums.size()) {
            nums[i] = 0;
            i++;
        }
    }
};

具体来说,我们定义了两个指针 ij,并将它们都初始化为 0。然后,我们使用 j 来遍历整个数组,对于每个元素,如果它不为 0,则将其复制到 nums[i] 的位置,并将 i 的值加 1。这样,i 就指向了下一个待填入非零元素的位置。当遍历完成后,所有非零元素都已经按照原来的顺序填充到数组的前面。

接下来,我们使用另一个 while 循环来将剩余的位置都填充为 0。具体来说,我们从 i 的位置开始,连续地将数组中的元素都赋值为 0,直到数组的末尾。

需要注意的是,这个算法的时间复杂度是 O(n),其中 n 表示数组的长度。由于只需要使用常数个额外变量,因此空间复杂度是 O(1)。

说明:输入 [0,1,0,3,12]

1. 初始化两个指针 `i` 和 `j`,它们都从 0 开始。
2. 使用一个 while 循环遍历整个数组,当 `j` 指针小于数组长度时,进入循环。
3. 如果 `nums[j]` 不等于 0,将 `nums[j]` 的值赋给 `nums[i]`,然后将指针 `i` 向前移动一位。
4. 不论 `nums[j]` 是否等于 0,指针 `j` 都会向前移动一位。

下面是对这段代码在给定数组 `[0, 1, 0, 3, 12]` 上的执行过程的详细说明:

1. 初始化:`i = 0`, `j = 0`, `nums = [0, 1, 0, 3, 12]`
2. `j = 0`,`nums[j] = 0`,跳过。`i = 0`, `j = 1`
3. `j = 1`,`nums[j] = 1`,`nums[i] = nums[j]`。`nums = [1, 1, 0, 3, 12]`。`i = 1`, `j = 2`
4. `j = 2`,`nums[j] = 0`,跳过。`i = 1`, `j = 3`
5. `j = 3`,`nums[j] = 3`,`nums[i] = nums[j]`。`nums = [1, 3, 0, 3, 12]`。`i = 2`, `j = 4`
6. `j = 4`,`nums[j] = 12`,`nums[i] = nums[j]`。`nums = [1, 3, 12, 3, 12]`。`i = 3`, `j = 5`
7. `j >= nums.size()`,循环结束。

此时,非零元素已经按照相对顺序移动到数组的前面。

进阶:你能尽量减少完成的操作次数吗?

为了减少完成操作的次数,我们可以对上面的双指针算法稍作修改。这里,我们将在遇到非零元素时直接与指针 i 所指向的元素进行交换,而不是简单地将非零元素赋值给 nums[i]。这样,当指针 j 遍历完整个数组后,我们就完成了整个过程,无需再遍历一次数组来填充 0。

以下是修改后的代码:

void moveZeroes(std::vector<int>& nums) {
    int i = 0;

    for (int j = 0; j < nums.size(); ++j) {
        if (nums[j] != 0) {
            // 当 i != j 时,交换元素;当 i == j 时,不进行操作
            if (i != j) {
                std::swap(nums[i], nums[j]);
            }
            i++;
        }
    }
}

这种方法在一次遍历中完成了操作,减少了操作次数。在最好的情况下,即数组中没有 0,这个算法的操作次数将是原来的一半。在最坏的情况下,即数组中全是 0,这个算法的操作次数将与原来相同。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

楚歌again

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值