提供的爬取软件来源于:52pojie.cn@夜泉 免费下载使用

LeetCode - 026 - 删除排序数组中的重复项(remove-duplicates-from-sorted-array

jsliang 飘飞的心灵 2019-06-07

Create by jsliang on 2019-06-06 11:11:26
Recently revised in 2019-06-06 14:30:57

一 目录

不折腾的前端,和咸鱼有什么区别

| 目录 | | --- | | 一 目录 | | 二 前言 | | 三 解题 | |  3.1 解法 - 双指针 | |  3.2 解法 - 违规操作 |

二 前言

  • 难度:简单

  • 涉及知识:数组、双指针

  • 题目地址:https://leetcode-cn.com/problems/remove-duplicates-from-sorted-array/

  • 题目内容

  1. 给定一个排序数组,你需要在原地删除重复出现的元素,使得每个元素只出现一次,返回移除后数组的新长度。

  2. 不要使用额外的数组空间,你必须在原地修改输入数组并在使用 O(1) 额外空间的条件下完成。

  3. 示例 1:

  4. 给定数组 nums = [1,1,2],

  5. 函数应该返回新的长度 2, 并且原数组 nums 的前两个元素被修改为 1, 2

  6. 你不需要考虑数组中超出新长度后面的元素。

  7. 示例 2:

  8. 给定 nums = [0,0,1,1,1,2,2,3,3,4],

  9. 函数应该返回新的长度 5, 并且原数组 nums 的前五个元素被修改为 0, 1, 2, 3, 4

  10. 你不需要考虑数组中超出新长度后面的元素。

  11. 说明:

  12. 为什么返回数值是整数,但输出的答案是数组呢?

  13. 请注意,输入数组是以“引用”方式传递的,这意味着在函数里修改输入数组对于调用者是可见的。

  14. 你可以想象内部操作如下:

  15. // nums 是以“引用”方式传递的。也就是说,不对实参做任何拷贝

  16. int len = removeDuplicates(nums);

  17. // 在函数里修改输入数组对于调用者是可见的。

  18. // 根据你的函数返回的长度, 它会打印出数组中该长度范围内的所有元素。

  19. for (int i = 0; i < len; i++) {

  20. print(nums[i]);

  21. }

三 解题

  • 官方题解:https://leetcode-cn.com/problems/remove-duplicates-from-sorted-array/solution/shan-chu-pai-xu-shu-zu-zhong-de-zhong-fu-xiang-by-/

解题千千万,官方独一家,上面是官方使用 Java 进行的题解。

小伙伴可以先自己在本地尝试解题,再看看官方解题,最后再回来看看 jsliang 讲解下使用 JavaScript 的解题思路。

3.1 解法 - 双指针

  • 解题代码

  1. var removeDuplicates = function(nums) {

  2. for (let i = 0; i < nums.length; i++) {

  3. if (nums[i] === nums[i + 1]) {

  4. nums.splice(i, 1);

  5. i--;

  6. }

  7. }

  8. };

  • 执行测试

  1. nums: [1,1,2]

  2. return

  1. 2

  • LeetCode Submit

  1. Accepted

  2. 161/161 cases passed (124 ms)

  3. Your runtime beats 72.77 % of javascript submissions

  4. Your memory usage beats 15.24 % of javascript submissions (37.6 MB)

  • 知识点

  1. splice(): splice() 方法通过删除或替换现有元素或者原地添加新的元素来修改数组,并以数组形式返回被修改的内容。此方法会改变原数组。 splice() 详细介绍

  • 解题思路

首先,这道题涉及到所谓的 双指针 了,什么是 双指针 呢?

  • 《LeetBook(LeetCode详解)》 - 双指针

双指针,顾名思义,就是利用两个指针去遍历数组,一般来说,遍历数组采用的是单指针(index) 去遍历,两个指针一般是在有序数组中使用,一个放首,一个放尾,同时向中间遍历,直到两个指针相交,完成遍历,时间复杂度也是O(n)。

啥意思咧?就好比我们的代码:

  1. for (let i = 0; i < nums.length; i++) {

  2. if (nums[i] === nums[i + 1]) {

  3. nums.splice(i, 1);

  4. i--;

  5. }

  6. }

在这里,我们是不是使用了数组的两个位置? [i] 以及 [i+1]

通过这两个指针的不断移动,直到把整个数组遍历一次,从而得到最终解。

然后,我们需要知道的是,由于代码中,我们使用了 for() + splice(),从而造成的耗时和空间会比其他代码大,因为 splice() 是 JavaScript 封装好的方法。

是不是觉得无法理解?那么我们稍微看一眼 splice() 的源码吧:

仅仅看看就行了,这里不做过多讲解,刚兴趣的小伙伴可以前往 V8 引擎源码

  1. function ArraySplice(start, delete_count) {

  2. CHECK_OBJECT_COERCIBLE(this, "Array.prototype.splice");

  3. var num_arguments = arguments.length;

  4. var array = TO_OBJECT(this);

  5. var len = TO_LENGTH(array.length);

  6. var start_i = ComputeSpliceStartIndex(TO_INTEGER(start), len);

  7. var del_count = ComputeSpliceDeleteCount(delete_count, num_arguments, len, start_i);

  8. var deleted_elements = ArraySpeciesCreate(array, del_count);

  9. deleted_elements.length = del_count;

  10. var num_elements_to_add = num_arguments > 2 ? num_arguments - 2 : 0;

  11. if (del_count != num_elements_to_add && %object_is_sealed(array)) {

  12. throw %make_type_error(kArrayFunctionsOnSealed);

  13. } else if (del_count > 0 && %object_is_frozen(array)) {

  14. throw %make_type_error(kArrayFunctionsOnFrozen);

  15. }

  16. var changed_elements = del_count;

  17. if (num_elements_to_add != del_count) {

  18. // If the slice needs to do a actually move elements after the insertion

  19. // point, then include those in the estimate of changed elements.

  20. changed_elements += len - start_i - del_count;

  21. }

  22. if (UseSparseVariant(array, len, IS_ARRAY(array), changed_elements)) {

  23. %NormalizeElements(array);

  24. if (IS_ARRAY(deleted_elements)) %NormalizeElements(deleted_elements);

  25. SparseSlice(array, start_i, del_count, len, deleted_elements);

  26. SparseMove(array, start_i, del_count, len, num_elements_to_add);

  27. } else {

  28. SimpleSlice(array, start_i, del_count, len, deleted_elements);

  29. SimpleMove(array, start_i, del_count, len, num_elements_to_add);

  30. }

  31. // Insert the arguments into the resulting array in

  32. // place of the deleted elements.

  33. var i = start_i;

  34. var arguments_index = 2;

  35. var arguments_length = arguments.length;

  36. while (arguments_index < arguments_length) {

  37. array[i++] = arguments[arguments_index++];

  38. }

  39. array.length = len - del_count + num_elements_to_add;

  40. // Return the deleted elements.

  41. return deleted_elements;

  42. }

如上, splice() 先执行删除操作,删除指定个数的元素,然后再插入 elements(元素或数组),他的每次删除都涉及大量元素的重新排列,而在插入元素时引入队列来管理。所以 splice() 的效率不高

最后,我们要做的就是返回数组的长度,就这样就 OK 了。

3.2 解法 - 违规操作

  • 解题代码

  1. var removeDuplicates = function(nums) {

  2. var a = [...new Set(nums)];

  3. for (var i = 0;i < a.length;i++) nums[i] = a[i];

  4. return a.length;

  5. };

  • 执行测试

  1. nums: [1,1,2]

  2. return

  1. 2

  • LeetCode Submit

  1. Accepted

  2. 161/161 cases passed (112 ms)

  3. Your runtime beats 93.2 % of javascript submissions

  4. Your memory usage beats 45.6 % of javascript submissions (37.1 MB)

  • 知识点

  1. Set: Set 对象允许你存储任何类型的唯一值,无论是原始值或者是对象引用。 Set 详细介绍

  • 解题思路

首先jsliang 表示这种方法可能不符合题意,但是它又是可行的!所以不管怎么说,莽就对了~

然后Set 对象会对值进行唯一操作,如果输入 [1,1,2],那么这个 Set 会变成 Set(2) {1,2}leta=newSet([1,1,2]);

接着,我们利用 ES6 的扩展运算符: [...newSet(nums)],可以直接将 Set 类型转换成 Array 类型。

最后,循环遍历 a,将 a 的内容赋值到 nums 即可(注意, nums 后面还是会有一些乱七八糟的数据,不过它不影响我们的解题)。


jsliang 广告推送:
也许小伙伴想了解下云服务器
或者小伙伴想买一台云服务器
或者小伙伴需要续费云服务器
欢迎点击 云服务器推广 查看!


jsliang 的文档库 由 梁峻荣 采用 知识共享 署名-非商业性使用-相同方式共享 4.0 国际 许可协议进行许可。
基于https://github.com/LiangJunrong/document-library上的作品创作。
本许可协议授权之外的使用权限可以从 https://creativecommons.org/licenses/by-nc-sa/2.5/cn/ 处获得。


精选留言

暂无...
吾爱破解论坛