移除元素OJ详解

一、题目介绍

给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素。元素的顺序可能发生改变。然后返回 nums 中与 val 不同的元素的数量。

假设 nums 中不等于 val 的元素数量为 k,要通过此题,您需要执行以下操作:

  • 更改 nums 数组,使 nums 的前 k 个元素包含不等于 val 的元素。nums 的其余元素和 nums 的大小并不重要。
  • 返回 k

用户评测:

评测机将使用以下代码测试您的解决方案:

int[] nums = [...]; // 输入数组
int val = ...; // 要移除的值
int[] expectedNums = [...]; // 长度正确的预期答案。
                            // 它以不等于 val 的值排序。

int k = removeElement(nums, val); // 调用你的实现

assert k == expectedNums.length;
sort(nums, 0, k); // 排序 nums 的前 k 个元素
for (int i = 0; i < actualLength; i++) {
    assert nums[i] == expectedNums[i];
}

如果所有的断言都通过,你的解决方案将会 通过

示例 1:

输入:nums = [3,2,2,3], val = 3
输出:2, nums = [2,2,_,_]
解释:你的函数函数应该返回 k = 2, 并且 nums 中的前两个元素均为 2。
你在返回的 k 个元素之外留下了什么并不重要(因此它们并不计入评测)。

示例 2:

输入:nums = [0,1,2,2,3,0,4,2], val = 2
输出:5, nums = [0,1,4,0,3,_,_,_]
解释:你的函数应该返回 k = 5,并且 nums 中的前五个元素为 0,0,1,3,4。
注意这五个元素可以任意顺序返回。
你在返回的 k 个元素之外留下了什么并不重要(因此它们并不计入评测)。

提示:

  • 0 <= nums.length <= 100
  • 0 <= nums[i] <= 50
  • 0 <= val <= 100

方法一:双指针法

  1. 使用两个指针,一个i用于遍历数组,另一个j用于记录不等于val的元素的位置。
  2. 遍历数组nums,当遇到不等于val的元素时,将其与j位置的元素交换,并将j加1。
  3. 遍历结束后,j的位置就是不等于val的元素的数量。
int removeElement(int* nums, int numsSize, int val) {
    int left = 0;
    for (int right = 0; right < numsSize; right++) {
        if (nums[right] != val) {
            nums[left] = nums[right];
            left++;
        }
    }
    return left;
}
  1. 函数定义

    • int removeElement(int* nums, int numsSize, int val):定义了一个函数removeElement,它接收三个参数:
      • int* nums:指向整数数组的指针,表示输入的数组。
      • int numsSize:数组nums的大小。
      • int val:需要从数组中移除的特定值。
  2. 初始化指针

    • int left = 0;:定义了一个变量left并初始化为0,它将用作记录不等于val的元素在数组中的新位置。
  3. 遍历数组

    • for (int right = 0; right < numsSize; right++):使用一个for循环遍历数组nums,其中right变量作为当前遍历到的元素的索引。
  4. 条件判断

    • if (nums[right] != val):如果当前遍历到的元素nums[right]不等于val,则执行以下操作。
  5. 元素交换

    • nums[left] = nums[right];:将当前遍历到的不等于val的元素复制到left索引的位置。这实际上是将不等于val的元素向前移动。
  6. 更新left指针

    • left++;:由于已经将一个不等于val的元素移动到了数组的前面,因此将left指针向前移动一位,为下一个不等于val的元素腾出空间。
  7. 返回结果

    • return left;:在遍历完数组后,left变量的值即为不等于val的元素的数量。函数返回这个值。

方法二:双指针优化

如果要移除的元素恰好在数组的开头,例如序列 [1,2,3,4,5],当 val 为 1 时,我们需要把每一个元素都左移一位。注意到题目中说:「元素的顺序可以改变」。实际上我们可以直接将最后一个元素 5 移动到序列开头,取代元素 1,得到序列 [5,2,3,4],同样满足题目要求。这个优化在序列中 val 元素的数量较少时非常有效。

实现方面,我们依然使用双指针,两个指针初始时分别位于数组的首尾,向中间移动遍历该序列。

int removeElement(int* nums, int numsSize, int val) {
    // 初始化两个指针,left指向数组开头,right指向数组末尾
    int left = 0, right = numsSize - 1;

    while (left < right) {
        // 如果left指向的元素等于val,尝试用right指向的元素替换它
        while (left < right && nums[left] == val) {
            left++;  // 移动left指针,跳过所有等于val的元素
        }
        // 如果right指向的元素不等于val,且left < right,交换两个元素
        if (left < right && nums[right] != val) {
            swap(nums, left, right);
            left++;  // 交换后,left指向的元素已经是不等于val的元素,所以left向前移动
            right--; // 同时right也向后移动,因为已经交换了元素
        }
        // 如果right指向的元素等于val,right向后移动
        else if (nums[right] == val) {
            right--;
        }
        // 如果left指向的元素不等于val,且right指向的元素也不等于val,不做操作
    }

    // 返回不等于val的元素的数量
    return left;
}

// 辅助函数,用于交换数组中的两个元素
void swap(int* a, int* b) {
    int temp = *a;
    *a = *b;
    *b = temp;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值