IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> leetcode初级算法题--原地删除排序数组中的重复项 -> 正文阅读

[数据结构与算法]leetcode初级算法题--原地删除排序数组中的重复项

博客主页:https://tomcat.blog.csdn.net
博主昵称:农民工老王
主要领域:Java、Linux、K8S
期待大家的关注💖点赞👍收藏?留言💬
家乡
创作申明
本文是一篇针对leetcode算法题的解题博客。我给出的解题思路和代码,以及对优质解答的讲解 均属于原创内容,本文的原创标识也是基于此。而题目全部出自leetcode.cn,优质解答搜索自全网,本文已经标明其引用出处。

我是一个算法初学者,完全的菜鸟,文中的算法题属于入门级别。本文适合算法新手阅读,而对算法大佬没有任何阅读价值。

题目

题目链接:https://leetcode.cn/leetbook/read/top-interview-questions-easy/x2gy9m/

题干

给你一个 升序排列 的数组 nums ,请你 原地 删除重复出现的元素,使每个元素 只出现一次 ,返回删除后数组的新长度。元素的 相对顺序 应该保持 一致 。

由于在某些语言中不能改变数组的长度,所以必须将结果放在数组nums的第一部分。更规范地说,如果在删除重复项之后有 k 个元素,那么 nums 的前 k 个元素应该保存最终结果。

将最终结果插入 nums 的前 k 个位置后返回 k 。

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

示例 1

输入:nums = [1,1,2]
输出:2, nums = [1,2,_]
解释:函数应该返回新的长度 2 ,并且原数组 nums 的前两个元素被修改为 1, 2 。不需要考虑数组中超出新长度后面的元素。

示例 2

输入:nums = [0,0,1,1,1,2,2,3,3,4]
输出:5, nums = [0,1,2,3,4]
解释:函数应该返回新的长度 5 , 并且原数组 nums 的前五个元素被修改为 0, 1, 2, 3, 4 。不需要考虑数组中超出新长度后面的元素。

题目分析

这个题的难点是“原地”,也就是说不能再新建一个数组。

我的解答

本题用Java实现。

我在审题时就出问题了,忽略了字符串是有序的这一重要信息。在这个情况下,我开始了自己的解答,我的计划是将整个目标分为两步走,先实现去重,再实现元素的顺序保持一致。

第一步,实现去重,我的思路是双重遍历如果发现重复的,就用最后一位有效元素覆盖重复元素,然后最后一位有效元素就用0覆盖。

public int removeDuplicates(int[] nums) {
    int del = 0;
    int oldLength = nums.length;
    for (int i = 0; i < oldLength - 1; i++) {
        for (int j = i + 1; j < oldLength - del; j++) {
            if (nums[i] == nums[j]) {
                nums[i] = nums[oldLength - 1 - del];
                nums[oldLength - 1 - del] = 0;
                del++;
            }
        }
    }
    return oldLength - del;
}

用下面的测试代码检测,证明能实现既定目标。

@Test
public void test(){
    int[] ints = {0, 0, 1, 1, 1, 2, 2, 3, 3, 4};
    int result = removeDuplicates(ints);
    System.out.println("返回值:" + result);
    System.out.println("-------------");
    System.out.print("结果:");
    for (int i = 0; i < result; i++) {
        System.out.print(ints[i] + " ");
    }
    System.out.println("");
}

在这里插入图片描述

第二步,在元素的顺序保持一致前提下实现去重,我的思路是双重遍历,如果发现重复的,把后面的元素全部前移一位,就直接覆盖了那个重复元素。但是在这种情况下,内层遍历的数组索引不应该增加,因为当前索引的重复元素已经被覆盖,现在是一个新的元素,所以应该继续判断当前索引。而如果发现当前索引的元素不是重复元素,才应该向后移动索引。所以内层最好是用while循环。

public int removeDuplicates(int[] nums) {
    int del = 0;
    int oldLength = nums.length;
    for (int i = 0; i < oldLength  - del- 1; i++) {
        int j = i + 1;
        // 此处一定注意减去del,否则会导致死循环
        while (j < oldLength-del) {
            if (nums[i] == nums[j]) {
                for (int k = j; k < oldLength - del -1; k++) {
                    nums[k] = nums[k + 1];
                }
                nums[oldLength - 1] = 0;
                del++;
            }else {
                j++;
            }
        }
    }
    return oldLength - del;
}

用上面的测试代码检测,发现完成了题目要求的目标。

在这里插入图片描述
提交到leetcode后也是通过了的,只是说时间复杂度上太高。
在这里插入图片描述

优质解答

leetcode网页中,题目下面的第一条讨论(作者力扣id:数据结构和算法)中提到的答案就非常优质,获得了很多人的点赞和认同。

直到看到了这位大佬的解析,我才发现数组升序是非常重要的参考因素。不过在我知道这个信息后,我也尝试了自己独立思考,找出相对于上面的解答更高效的解答,但还是没有思绪。然后我就认真阅读了这位大佬的答案。

他的关键词是双指针,实质上是用两个指针把数组中不重复的元素移动到数组最前面,的确非常高效,时间复杂度只有O(n)。

右指针的作用是扫描整个数组,所以无论任何情况它都要向右移动,所以将右指针写在了for循环的条件里。左指针的初始值是0,右指针的初始值是1,这样才可以开始比较。如果左指针和右指针指向的值一样,说明右指针上面的是重复值,就可以直接跳过,体现在代码上,就是,不做任何操作不处理,不过右指针还是会在for循环的运行下向右移。如果两个指针对应的值不一样,就说明右指针上的值需要被记录,这时候需要先把左指针加1,这样左指针就指向了一个新的位置,就可以存放右指针的值。

总之,就是右指针扫描,左指针存值。

public int removeDuplicates(int[] A) {
    //边界条件判断
    if (A == null || A.length == 0)
        return 0;
    int left = 0;
    for (int right = 1; right < A.length; right++)
        if (A[left] != A[right]){
            A[++left] = A[right];
        }
    return ++left;
}

提交这位大佬的代码,其结果秒杀我上面的时间复杂度。不过我的内存消耗比他少。哈哈。
在这里插入图片描述
另外还有一点,就是我的代码兼容任何升序、降序、无序的数组,而这个参考答案仅仅使用于当前题目中的有序数组。如果用{0, 0, 1, 0, 1, 2, 2, 3, 3, 4}这个数组来测试,这个参考答案就不能实现去重,如图所示。
在这里插入图片描述
不过这也不在题目要求内。

总之和这个参考答案相比,我的解答就像一坨屎。此刻我只想对自己说:“老王,这就是差距啊,你要知耻啊!”


如需转载,请注明本文的出处:农民工老王的CSDN博客https://blog.csdn.net/monarch91 。

  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2022-05-12 16:37:25  更:2022-05-12 16:37:43 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 3:55:12-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码