• 26,27删除数组重复项


    26,27删除数组重复项

    题目

    题目26

    • 给定一个排序数组,你需要在原地删除重复出现的元素,使得每个元素只出现一次,返回移除后数组的新长度。
    • 不要使用额外的数组空间,你必须在原地修改输入数组并在使用 O(1) 额外空间的条件下完成。

    示例:

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

    题目27

    • 给定一个数组 nums 和一个值 val,你需要原地移除所有数值等于 val 的元素,返回移除后数组的新长度。
    • 不要使用额外的数组空间,你必须在原地修改输入数组并在使用 O(1) 额外空间的条件下完成。
    • 元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。

    示例:

    给定 nums = [3,2,2,3], val = 3,

    函数应该返回新的长度 2, 并且 nums 中的前两个元素均为 2。

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

    刚开始看完题目,不知道应该怎样去解决,为什么不创建新数组就可以“原地”删除元素,在参看力扣优秀解法之后,其实只要返回的新长度的范围内符合即可。

    双指针法

    题26解法

    首先题目是已经排序后的数组,在不考虑数组中超出新长度后面的元素的前提下,可以分别定义快慢指针(i是慢指针,j是快指针),如果重复(nums[i]==nums[j]的情况),直接跳过,将重复的一一向前覆盖(nums[++i] = nums[j];),最终返回新长度即可。

    /**
     * 删除数组中重复的项,并返回数组的长度
     * @param nums 传入已排序的数组
     * @return 返回无重复项数组的长度
     */
    public int removeDuplicates(int[] nums) {
        if (nums.length == 0) return 0;
        //定义慢指针
        int i = 0;
        //定义快指针
        for (int j = 1; j < nums.length; j++) {
            //相等情况直接跳过
            //不相等时,将nums[j]的值赋值给nums[i+1],然后递增i
            if (nums[j] != nums[i]) {
    
                nums[++i] = nums[j];
            }
        }
        //返回无重复项数组的新长度
        return i + 1;
    }
    

    题27解法一

    类似地,也可以运用双指针法求解。还是定义快慢两个指针,只要快指针索引值和目标值不相等,即nums[j]!=val,就可以将该索引值赋值给前面的慢指针索引值,即nums[i]=nums[j],两个指针同时递增,直到快指针截至,最终的新长度就是慢指针i的值。

     /**
     * 删除所有重复的val值,并返回数组的长度
     * @param nums 传入的数组
     * @param val  删除数组中的所有val
     * @return 返回无重复数组的长度
     */
    public int removeDuplicates(int[] nums, int val) {
    
        int i = 0;
        for (int j = 0; j < nums.length; j++) {
            if (nums[j] != val) {
                nums[i++] = nums[j];
            }
        }
        return i;
    }
    

    复杂度分析

    • 时间复杂度:O(n) 假设数组总共有n个元素,i和j分别最多遍历n步
    • 空间复杂度:O(1)

    题27解法二

    题27的解法一很暴力,但是在遇到特殊情况时其实进行了多余的步骤:假如数组包含需要删除的数很少的时候,nums=[4,1,2,3,5],val=4时,题目中特意提示可以不用考虑新数组的元素顺序,可以在遇到nums[i]==val时,将当前元素和最后一个元素交换,并释放数组的最后一个元素。

    如果被交换的最后一个元素正好也是想要删除的值,他会在下一次迭代时被发现。

    public int removeDuplicates00(int[] nums, int val) {
        int i = 0;
        //定义变量len操作数组长度,因为本身是final的
        int len = nums.length;
        while (i < len) {
    
            if (nums[i] == val) {
                //相等的情况,将第一个与最后一个交换,
                // 因为数组顺序可以更改,[4,1,2,3,5],val=4,
                //可以避免不必要的移位
                nums[i] = nums[len - 1];
                len--;
            } else {
                i++;
            }
        }
        return len;
    }
    

    复杂度分析

    • 时间复杂度:O(n),i和n最多遍历n步,且赋值操作的次数等于将要删除元素的数量,如果要移除的元素很少,效率会很高。
    • 空间复杂度:O(1)
  • 相关阅读:
    一个人的热闹
    关于Java单向链表头结点与头指针傻傻分不清
    Scanner输入的问题
    String、StringBuffer和StringBuilder的区别:
    偷吃的老人
    ubuntu 安装redis
    Ubuntu 安装 nginx
    谁再说不熟悉 Linux 命令,就把这个给他扔过去!
    ubuntu 安装mysql并设置密码
    题解 UOJ #99. 【集训队互测2015】普罗达科特
  • 原文地址:https://www.cnblogs.com/summerday152/p/12117224.html
Copyright © 2020-2023  润新知