首页 > 其他分享 >0基础leetcode练习(移动零)

0基础leetcode练习(移动零)

时间:2024-08-14 22:53:01浏览次数:7  
标签:count nums int 练习 非零 数组 移动 leetcode 指针

一、题目介绍

这是移动零的网址,大家可以看完博客的思路去练习一下。

给定一个数组 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

普通方法:

其实这个很简单,把非零都移到前面去之后,后面剩下的直接补0就好。

void moveZeroes(int* nums, int numsSize)
{
        int count = 0;
        for (int i = 0; i < numsSize; i++) 
        {
            if (nums[i] == 0)
            {
                count++;
                continue;
            }
            nums[i - count] = nums[i];
        }
       while (count-- > 0) {
    nums[numsSize - count - 1] = 0;
}
}

实现思路:

1. 初始化计数器:定义一个变量 `count` 来记录数组中零的个数。

2. 遍历数组:使用一个 `for` 循环遍历数组 `nums`。

3. 处理非零元素:在循环中,如果当前元素 `nums[i]` 不是零,就将其复制到索引 `i - count` 的位置。由于 `count` 记录了前面有多少个零,所以 `i - count` 就是当前非零元素应该在的位置。

4. 更新计数器:如果当前元素是零,`count` 就递增,表示遇到了一个零值,但是不进行元素交换,因为零值将在后面统一处理。

5. 填充零值:在 `for` 循环结束后,使用一个 `while` 循环从数组的末尾向前填充零。由于前面已经将所有非零元素移动到了数组的前部,所以数组的末尾 `count` 个位置需要填充零。

6. 更新数组:在 `while` 循环中,每次循环将数组的倒数第 `count` 个位置设置为零,并且 `count` 递减。这样,每次循环都将零放在正确的位置,直到 `count` 变为零。

7. 循环结束:当 `count` 变为零时,所有的零都被移动到了数组的末尾,且非零元素的相对顺序没有改变。

这段代码的关键在于使用一个计数器 `count` 来跟踪零的数量,并在遍历过程中将非零元素移动到数组的前部。然后,使用另一个循环将剩余的位置填充为零。这种方法的时间复杂度是 O(n),其中 n 是数组 `nums` 的长度,因为我们只遍历了数组两次(一次移动非零元素,一次填充零)。空间复杂度是 O(1),因为我们只使用了有限的额外空间(即 `count` 变量)。

双指针方法:

void swap(int *a, int *b) {
    int t = *a;
    *a = *b, *b = t;
}

void moveZeroes(int *nums, int numsSize) {
    int left = 0, right = 0;
    while (right < numsSize) {
        if (nums[right]) {
            swap(nums + left, nums + right);
            left++;
        }
        right++;
    }
}

思路及解法

使用双指针,左指针指向当前已经处理好的序列的尾部,右指针指向待处理序列的头部。

右指针不断向右移动,每次右指针指向非零数,则将左右指针对应的数交换,同时左指针右移。

注意到以下性质:

左指针左边均为非零数;

右指针左边直到左指针处均为零。

因此每次交换,都是将左指针的零与右指针的非零数交换,且非零数的相对顺序并未改变。

交换法:

void moveZeroes(int* nums, int numsSize) {
    // `j` 指向数组中下一个非零元素应该放置的位置
    int j = 0;

    // 遍历数组
    for (int i = 0; i < numsSize; i++) {
        // 如果当前元素不是零,则将其移动到 `j` 的位置
        if (nums[i] != 0) {
            nums[j++] = nums[i]; // 将非零元素复制到 `j` 的位置,并递增 `j`
        }
    }

    // 此时 `j` 指向数组中第一个零的位置
    // 从 `j` 开始填充零,直到数组末尾
    for (; j < numsSize; j++) {
        nums[j] = 0;
    }
}

实现思路:

  1. 初始化指针:定义一个指针 j,它用来指向数组中下一个非零元素应该放置的位置。

  2. 遍历数组:使用一个 for 循环遍历数组 nums

  3. 处理非零元素:在循环中,如果当前元素 nums[i] 不是零,就将其复制到索引 j 的位置。然后递增 j,准备放置下一个非零元素。

  4. 省略条件判断:由于 j 总是指向下一个非零元素应该放置的位置,所以不需要检查 ij 是否相等,直接进行赋值和 j 的递增。

  5. 填充零值:在 for 循环结束后,j 将指向数组中第一个零应该放置的位置。此时,使用另一个 for 循环从 j 开始,将数组的剩余位置填充为零。

  6. 循环结束:第二个 for 循环继续执行,直到 j 达到数组末尾 numsSize,确保所有剩余的位置都被设置为零。

  7. 原地操作:整个操作都在原数组 nums 上进行,没有使用额外的数组空间,因此是原地(in-place)操作。

  8. 时间复杂度:这个算法的时间复杂度是 O(n),其中 n 是数组 nums 的长度,因为我们只遍历了数组两次(一次移动非零元素,一次填充零)。

  9. 空间复杂度:空间复杂度是 O(1),因为我们只使用了有限的额外空间(即 j 变量)。

 本期内容向大家介绍了这道OJ题的三种做法,其实这些思想可以贯穿到很多题中,大家平时要多加练习,才能写出更好更妙的代码。加油各位!

标签:count,nums,int,练习,非零,数组,移动,leetcode,指针
From: https://blog.csdn.net/Yyyyyyyyyyyyds/article/details/141176599

相关文章

  • 8.14 PTA练习
    3-11求一元二次方程的根本题目要求一元二次方程ax2+bx+c=0的根,结果保留2位小数。(注意:0.00会在gcc下被输出为-0.00,需要做特殊处理,输出正确的0.00。)输入格式:输入在一行中给出3个浮点系数a、b、c,中间用空格分开。输出格式:根据系数情况,输出不同结果:1)如果方程有两个不相等的......
  • LeetCode40.组合总和II
    LeetCode40.组合总和II力扣题目链接(opensnewwindow)给定一个数组candidates和一个目标数target,找出candidates中所有可以使数字和为target的组合。candidates中的每个数字在每个组合中只能使用一次。说明:所有数字(包括目标数)都是正整数。解集不能包含重复的组合。......
  • LeetCode39. 组合总和
    LeetCode39.组合总和题目叙述:给定一个无重复元素的数组candidates和一个目标数target,找出candidates中所有可以使数字和为target的组合。candidates中的数字可以无限制重复被选取。说明:所有数字(包括target)都是正整数。解集不能包含重复的组合。示例1:输入:ca......
  • LeetCode 3 无重复字符的最长子串
    题目描述给定一个字符串s,请你找出其中不含有重复字符的 最长子串 的长度。示例 1:输入:s="abcabcbb"输出:3解释:因为无重复字符的最长子串是"abc",所以其长度为3。示例2:输入:s="bbbbb"输出:1解释:因为无重复字符的最长子串是"b",所以其长度......
  • LeetCode 链表两数相加
    题目描述给你两个 非空的链表,表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的,并且每个节点只能存储 一位 数字。请你将两个数相加,并以相同形式返回一个表示和的链表。你可以假设除了数字0之外,这两个数都不会以0 开头。示例1:输入:l1=[2,4,3],......
  • LeetCode216.组合总和lll
    4.组合总和lll(LeetCode216)题目叙述:找出所有相加之和为n的k个数的组合,且满足下列条件:只使用数字1到9每个数字最多使用一次返回所有可能的有效组合的列表。该列表不能包含相同的组合两次,组合可以以任何顺序返回。示例1:输入:k=3,n=7输出:[[1,2,4]]解释:1......
  • leetcode面试经典150题- 380. O(1) 时间插入、删除和获取随机元素
     https://leetcode.cn/problems/insert-delete-getrandom-o1/description/?envType=study-plan-v2&envId=top-interview-150gotypeRandomizedSetstruct{isHavemap[int]inttotalintarr[]int}funcConstructor()RandomizedSet{retur......
  • C#字符串梳理及练习
    一、字符串API梳理:字符串:字符串不可以被修改,一般调用字符串API的时候使用新的变量来接收usingSystem;usingSystem.Linq;namespace_10.梳理字符串API{internalclassProgram{staticvoidMain(string[]args){//1。......
  • leetcode面试经典150题- 45. 跳跃游戏 II
    https://leetcode.cn/problems/jump-game-ii/description/?envType=study-plan-v2&envId=top-interview-150gopackageleetcode150import"testing"funcTestJump2(t*testing.T){nums:=[]int{5,9,3,2,1,0,2,3,3,1,0,0}res:=j......
  • 【数据结构】详细介绍线性表中的顺序表,带你复盘实现细节,附上顺序表编程练习题
    目录一.线性表二.顺序表 1.静态顺序表与动态顺序表2.动态顺序表的接口实现 2.1顺序表初始化 2.2判断是否需要扩容  2.3 顺序表指定位置插入2.4 顺序表头插2.5 顺序表尾插2.6 顺序表指定位置删除2.7 顺序表头删2.8 顺序表尾删2.9 顺序表查找2.1......