-
给你一个数组nums和一个值val,你需要原地移除所有数值等于val的元素,并且返回移除后数组的新长度。
- 不要使用额外的数组空间,你必须仅使用O(1)额外空间并原地修改输入的数组。
- 元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素
示例1:
给定 nums = [3,2,2,3], val = 3, 函数应该返回新的长度 2, 并且 nums 中的前两个元素均为 2。 你不需要考虑数组中超出新长度后面的元素。示例2:
给定 nums = [0,1,2,2,3,0,4,2], val = 2, 函数应该返回新的长度 5, 并且 nums 中的前五个元素为 0, 1, 3, 0, 4。 注意这五个元素可为任意顺序。 你不需要考虑数组中超出新长度后面的元素。说明
- 为什么返回数值是整数,但输出的答案是数组呢?
- 请注意,输入数组是以「引用」方式传递的,这意味着在函数里修改输入数组对于调用者是可见的。
- 你可以想象内部操作如下:
// nums 是以“引用”方式传递的。也就是说,不对实参作任何拷贝 int len = removeElement(nums, val); // 在函数里修改输入数组对于调用者是可见的。 // 根据你的函数返回的长度, 它会打印出数组中 该长度范围内 的所有元素。 for (int i = 0; i < len; i++) { print(nums[i]); }解题
// 你在原数组中进行修改,返回出目标数组的长度,超过这个长度的数组项可以继续留在原数组,长度以内的项就是结果项 // 1, 方法1 直接覆盖 // a. 遇到不同于val的项,就将它直接覆盖到nums数组中,从第一项开始覆盖。 // b. 遍历完数组, 不同于val的项都安排到了nums数组的前头。 let removeElement = (nums, val) => { let index = 0; for (let i = 0; i < nums.length; i++) { if (nums[i] !== val) { nums[index] = nums[i]; index++; } } return index; } console.log(removeElement([3, 5, 3, 6], 3)); // 方法2 末尾项覆盖 (双指针) // 指向头尾的双指针 // 遇到等于val的项,就拿数组的末尾项覆盖它 // 末尾项搬到前面来了,将尾指针左移一位 // 如果遇到不同于val的项,左指针就+1,考察下一项 // 循环结束的条件是两个指针交叉相遇 var removeElement = (nums, val) => { let index = 0, last = nums.length - 1 while (index <= last) { if (nums[index] === val) { nums[index] = nums[last] last-- } else { index++ } } return index } console.log(removeElement([3, 5, 3, 6, 3, 6, 6], 3)); // splice删除元素 // 遇到和val相同的,直接删除,导致后面的项前移一位 // 指针i要-1, 考察前移过来的新来的项,不然会漏掉考察它 let removeElement = (nums, val) => { for (let i = 0; i < nums.length; i++) { if (nums[i] === val) { nums.splice(i, 1); i--; } } return nums.length; } let arr = [1, 3, 1, 3, 4]; let arr1 = removeElement(arr, 3); console.log(arr1); // 每次都定位出要删除的那个 // 只要数组中还存在和val相同的项,就删除,删完了就返回数组的长度 let removeElement = (nums, val) => { while (nums.includes(val)) { nums.splice(nums.indexOf(val), 1); } return nums.length; } let a = removeElement([1, 3, 3, 2, 5], 3); console.log(a, 'a----');