LeetCode 283题:移动零

LeetCode 283题:移动零 (Move Zeroes)

LeetCode 第283题要求将数组中的所有零移动到数组的末尾,同时保持非零元素的相对顺序。


题目描述

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

注意:

  1. 必须在原数组上操作,不能拷贝额外的数组。
  2. 尽量减少操作次数。

示例

示例 1

text 复制代码
输入: nums = [0,1,0,3,12]
输出: [1,3,12,0,0]

示例 2

text 复制代码
输入: nums = [0,0,1]
输出: [1,0,0]

解题思路

  1. 双指针法

    • 定义两个指针:ij
    • i 指向非零元素要存储的位置,j 遍历整个数组寻找非零元素。
    • 如果找到非零元素,则将其移动到 i 的位置,并将 i 向后移动。
    • 最后,从 i 开始的剩余位置填充为零。
  2. 遍历两次

    • 第一次遍历数组,将所有非零元素移到前面。
    • 第二次从非零结束的位置开始,将剩余的位置填充为零。
  3. 复杂度分析

    • 时间复杂度 : O ( n ) O(n) O(n),其中 n n n 是数组的长度,只需遍历数组两次。
    • 空间复杂度 : O ( 1 ) O(1) O(1),没有使用额外的数组存储。

C语言代码实现

以下是基于双指针的代码实现:

c 复制代码
#include <stdio.h>

/**
 * 移动零
 * @param nums: 输入数组
 * @param numsSize: 数组的大小
 */
void moveZeroes(int* nums, int numsSize) {
    int i = 0; // i 指向非零元素要存储的位置
    for (int j = 0; j < numsSize; j++) {
        if (nums[j] != 0) {  // 如果找到非零元素
            nums[i] = nums[j]; // 将非零元素移动到索引 i 的位置
            i++;               // 更新 i 的位置
        }
    }
    for (; i < numsSize; i++) {
        nums[i] = 0; // 将剩余的位置填充为 0
    }
}

int main() {
    int nums1[] = {0, 1, 0, 3, 12};
    int nums2[] = {0, 0, 1};

    moveZeroes(nums1, 5);
    moveZeroes(nums2, 3);

    printf("Test Case 1: ");
    for (int i = 0; i < 5; i++) {
        printf("%d ", nums1[i]);
    }
    printf("\n");

    printf("Test Case 2: ");
    for (int i = 0; i < 3; i++) {
        printf("%d ", nums2[i]);
    }
    printf("\n");

    return 0;
}

逐行解释代码

函数 moveZeroes
c 复制代码
void moveZeroes(int* nums, int numsSize) {
    int i = 0; // i 指向非零元素要存储的位置
  • 定义一个指针 i,用于记录非零元素存储的目标位置,初始值为 0。
c 复制代码
    for (int j = 0; j < numsSize; j++) {
        if (nums[j] != 0) {  // 如果找到非零元素
            nums[i] = nums[j]; // 将非零元素移动到索引 i 的位置
            i++;               // 更新 i 的位置
        }
    }
  • 使用指针 j 遍历数组:
    • 如果 nums[j] != 0,说明当前元素是非零,将其移动到 nums[i]
    • 然后将 i 向后移动,以便存储下一个非零元素。
c 复制代码
    for (; i < numsSize; i++) {
        nums[i] = 0; // 将剩余的位置填充为 0
    }
  • 遍历结束后,指针 i 指向非零元素的最后一个位置。
  • i 开始,将数组剩余的所有位置填充为 0

测试代码 main
c 复制代码
int main() {
    int nums1[] = {0, 1, 0, 3, 12};
    int nums2[] = {0, 0, 1};

    moveZeroes(nums1, 5);
    moveZeroes(nums2, 3);

    printf("Test Case 1: ");
    for (int i = 0; i < 5; i++) {
        printf("%d ", nums1[i]);
    }
    printf("\n");

    printf("Test Case 2: ");
    for (int i = 0; i < 3; i++) {
        printf("%d ", nums2[i]);
    }
    printf("\n");

    return 0;
}
  • 定义了两个测试用例:
    • nums1 = {0, 1, 0, 3, 12}
    • nums2 = {0, 0, 1}
  • 调用 moveZeroes 函数进行操作。
  • 打印出修改后的数组,验证结果。

测试结果

运行代码后输出:

text 复制代码
Test Case 1: 1 3 12 0 0 
Test Case 2: 1 0 0 

复杂度分析

  1. 时间复杂度

    • 遍历数组两次,每次 O ( n ) O(n) O(n),总复杂度为 O ( n ) O(n) O(n)。
  2. 空间复杂度

    • 没有使用额外存储,空间复杂度为 O ( 1 ) O(1) O(1)。
相关推荐
Jasmine_llq2 分钟前
《P3157 [CQOI2011] 动态逆序对》
算法·cdq 分治·动态问题静态化+双向偏序统计·树状数组(高效统计元素大小关系·排序算法(预处理偏序和时间戳)·前缀和(合并单个贡献为总逆序对·动态问题静态化
爱吃rabbit的mq40 分钟前
第09章:随机森林:集成学习的威力
算法·随机森林·集成学习
(❁´◡`❁)Jimmy(❁´◡`❁)1 小时前
Exgcd 学习笔记
笔记·学习·算法
YYuCChi2 小时前
代码随想录算法训练营第三十七天 | 52.携带研究材料(卡码网)、518.零钱兑换||、377.组合总和IV、57.爬楼梯(卡码网)
算法·动态规划
不能隔夜的咖喱2 小时前
牛客网刷题(2)
java·开发语言·算法
VT.馒头2 小时前
【力扣】2721. 并行执行异步函数
前端·javascript·算法·leetcode·typescript
进击的小头2 小时前
实战案例:51单片机低功耗场景下的简易滤波实现
c语言·单片机·算法·51单片机
咖丨喱4 小时前
IP校验和算法解析与实现
网络·tcp/ip·算法
罗湖老棍子4 小时前
括号配对(信息学奥赛一本通- P1572)
算法·动态规划·区间dp·字符串匹配·区间动态规划
fengfuyao9854 小时前
基于MATLAB的表面织构油润滑轴承故障频率提取(改进VMD算法)
人工智能·算法·matlab