力扣面试150题-删除有序数组中的重复项和删除有序数组中的重复项II

day 2

删除有序数组中的重复项(简单)

题目描述

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

考虑 nums 的唯一元素的数量为 k ,你需要做以下事情确保你的题解可以被通过:

更改数组 nums ,使 nums 的前 k 个元素包含唯一元素,并按照它们最初在 nums 中出现的顺序排列。nums 的其余元素与 nums 的大小不重要。
返回 k 。
判题标准:

系统会用下面的代码来测试你的题解:

int[] nums = […]; // 输入数组
int[] expectedNums = […]; // 长度正确的期望答案

int k = removeDuplicates(nums); // 调用

assert k == expectedNums.length;
for (int i = 0; i < k; i++) {
assert nums[i] == expectedNums[i];
}
如果所有断言都通过,那么您的题解将被 通过

示例

示例 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 。不需要考虑数组中超出新长度后面的元素

思路

最简单的想法
因为这个数组是递增的,那么数组末尾必然是数组最大的,那么当发现一个元素是重复的,先让计数器++,并将其值改为最大值,遍历到数组末尾,采取Array.sort(),所有最大值都会落在数组末尾,同时也能保持数组的相对顺序一致。

class Solution {
    public int removeDuplicates(int[] nums) {
        int i;
        int sum=1;
        int max=nums[nums.length-1];
        for(i=1;i<nums.length;i++){
            if(nums[i-1]==nums[i]){
                nums[i-1]=max;
            }
            else{
                sum++;
            }
        }
        Arrays.sort(nums);
        return sum;
    }
}

存在问题
没有考虑时间复杂度。
双指针解法
由于数组是递增的,那么如果一个元素和前一个元素不同,则说明这个元素是找到的第一个不重复元素(后买你可能也会与这个重复的),由此可以定义两个参数fast和slow:
fast用于比较一个元素和前一个元素,如果不同则说明这个是不重复的,将其插入到slow的位置
slow用于指示插入的位置,由于要找到的是一个不重复的数组,直接slow++即可。
特殊情况处理一下:数组长度为0直接返回即可。

class Solution {
    public int removeDuplicates(int[] nums) {
      int fast,slow,n;
      fast=slow=1;//由于第一个元素肯定是一段重复元素的第一个,直接设定为1,
      n=nums.length;
      if(n==0){
        return 0;
      }
      while(fast<n){//fast到最后一个元素结束
        if(nums[fast]!=nums[fast-1]){
            nums[slow]=nums[fast];
            slow++;
        }
        fast++;
      }
      return slow;
    }
}

删除有序数组中的重复项II(中等)

题目描述

给你一个有序数组 nums ,请你 原地 删除重复出现的元素,使得出现次数超过两次的元素只出现两次 ,返回删除后数组的新长度。

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

说明

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

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

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

// nums 是以“引用”方式传递的。也就是说,不对实参做任何拷贝
int len = removeDuplicates(nums);

// 在函数里修改输入数组对于调用者是可见的。
// 根据你的函数返回的长度, 它会打印出数组中 该长度范围内 的所有元素。
for (int i = 0; i < len; i++) {
print(nums[i]);
}

示例

示例 1

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

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

思路

这道题与上一题的差别在于,允许一个元素出现两次
初次想法:延用上一题的最简单粗暴的做法,由于是递增数组,这种情况需要判断是否会出现3个重复的最大值,可能需要删除最大值,所以设置一个max=nums[nums.length-1]+1,来做替换值。
由于最多要保留两个重复值,则直接从第三个元素开始遍历,判断该元素是否同时与前面两个值相等(存在则有可能有三个重复 记录这个值test)或者该元素与前面重复的元素值相同(由于比较的是前两个元素,会修改第三个元素,则要与testt进行比较)。
循环中计数器sum++,test存放当前重复值,将该元素设置为max。(sum记录超过两个重复值的元素个数)
最后进行Arrays.sort(),返回nums.length - sum。

class Solution {
    public int removeDuplicates(int[] nums) {
        int sum = 0;
        int max = nums[nums.length - 1] + 1; 
        int test=max;
        int i = 0;
        if(nums.length>2){
        for (i = 2; i < nums.length; i++) {
            if ((nums[i] == nums[i - 1] && nums[i] == nums[i - 2])||(test==nums[i])) {// 该删
                sum++;
                test=nums[i];
                nums[i] = max;
            }}
            Arrays.sort(nums);
        return nums.length - sum;}
        else{
            return nums.length;
        }
    }
}

双指针解法基于上一题的双指针进行修改,
特殊情况:数组小于2则直接返回即可。
test用于存放已经重复过两次的元素值。
循环中判断,fast指向的元素是否等于test
等于说明这是个重复两次以上的元素,不需要处理,等着被slow指针覆盖就行。
不等于说明这个元素不是重复两次以上的元素,但是有一下两种情况

  1. 这个元素与前一个元素相同,说明这是正好重复两次的元素,需要更新test值
  2. 这个元素值是目前第一次出现,不用额外处理
  3. 将这个值覆盖到slow即可,slow++即可。
class Solution {
    public int removeDuplicates(int[] nums) {
      int fast,slow,n,test;//test存放重复了两次的值
      n=nums.length;
        if(n<=2){//特殊情况 数组小于2则直接返回即可
        return 2;
      }
      fast=slow=2;//由于第一个元素肯定是一段重复元素的第一个,直接设定为1,
      if(nums[0]==nums[1]){
        test=nums[0];//如果前两个都是相等的,那么遍历的第一个就要删
      }
      else{
        test=nums[n-1]+1;//否则赋一个不存在的值
      }
      while(fast<n){//fast到最后一个元素结束
        if(nums[fast]!=test){//不为重复两次的值
            if(nums[fast-1]==nums[fast]){//判断这个是否和前一个相同,相同就要更新test
                test=nums[fast];
            }
            nums[slow]=nums[fast];
            slow++;
        }
        fast++;
      }
      return slow;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值