leetCode 编号26和80

80 阅读4分钟

26. 删除有序数组中的重复项:给你一个 非严格递增排列 的数组 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. 从题目和单元测试来看assert nums[i] == expectedNums[i];这部分代码来看,我们不仅仅需要返回去重后的数组长度,还需要将 原数组 中不重复的值,挪动到前K长度内,且题中说明nums的其余元素与nums的大小不重要
  2. 我想到的是两个思路:
    1. 将一个篮子内的鸡蛋,放到另一个鸡蛋中,放的过程中移除掉相同的鸡蛋
    2. 将原本篮子内的鸡蛋按要求重新排序,将后面未重复的挪动到前面
方法一
  1. 定义新的数组,用来放置未重复的值
  2. 更新原数组,并返回新数组长度

注意:更新原数组时,我一开始使用的是nums = [...resultArr],但结果就是并没有更新原数组,这里是因为刚开始我将nums数组当作函数removeDuplicates(nums)的参数传递时,传递的是数组nums的指针引用,使用nums = [...resultArr]重新赋值后,函数内部的nums的引用指针已经不是指在原数组上了,而是移动到新的数组[...resultArr]上,所以将不会改动原nums数组。而我们要做的就是直接修改函数内部的nums数组,此时函数内外的数组指向的都是同一个数组对象的引用,内外数组将同步修改结果,因为本就指向同一个数组对象

/**
 * @param {number[]} nums
 * @return {number}
 */
var removeDuplicates = function (nums) {
    let resultArr = []
    let newNums = [...nums]
    newNums.forEach((item, index) => {
        if (resultArr.indexOf(item) < 0) {
            resultArr.push(item)
        }
    })
    // nums = [...resultArr]
    nums.splice(0, nums.length)
    resultArr.forEach(item => nums.push(item));
    console.log('nums', nums)
    return resultArr.length
};
方法二
思路:
  1. 由于是 非严格递增排列 的数组,且nums的其余元素与nums的大小不重要,所以即使题目中声明元素的 相对顺序 应该保持 一致 ,我们仍然可以使用双指针的形式,来替换达到后元素前移的目的
  2. 首先声明并初始化let a = 0,从索引1开始遍历数组,当两指针的值不相同时,移动指针aa++,并将当前值赋值给指针a,遍历结束后,nums数组的不重复元素将前移,a+1则为不重复元素的个数
/**
 * @param {number[]} nums
 * @return {number}
 */
var removeDuplicates = function(nums) {
  let a = 0
  let len = nums.length
  for(let b = 1; b < len; b++) {
    if(nums[a] != nums[b]) {
        a++
        nums[a] = nums[b]
    }
  }
  return a + 1
};

80. 删除有序数组中的重复项 II:给你一个有序数组 nums ,请你 原地 删除重复出现的元素,使得出现次数超过两次的元素只出现两次 ,返回删除后数组的新长度。不要使用额外的数组空间,你必须在 原地 修改输入数组 并在使用 O(1) 额外空间的条件下完成。

方法一
思路:
  1. 思路和前一个差不多,只是从一个重复元素换到了两个,两个元素就往前多对比一个a-1的值就行
  2. 说白了就是3种情况
1. a != b
   a++
   nums[a] = nums[b]
2. a = b
   2.1 a - 1 != b
       a++
       nums[a] = nums[b]
   2.2 a - 1 = b

具体代码如下

/**
 * @param {number[]} nums
 * @return {number}
 */
var removeDuplicates = function (nums) {
    let a = 1
    let len = nums.length
    for (let b = 2; b < len; b++) {
        if (nums[a] != nums[b]) {
            a++
            nums[a] = nums[b]
        } else {
            if (nums[a - 1] != nums[b]) {
                a++
                nums[a] = nums[b]
            }
        }
    }
    return a + 1
};
方法二( 另一个作者的题解感觉比我的好 原作者题解
思路:
  1. 题中有说明1 <= nums.length <= 3 * 104,所以数组最少有2个值,而前两个值是否相同都满足题目要求
  2. 已经有排序的情况下,nums[i] === nums[i - 2]则直接nums.splice(i,1)删除原数组中的该值,删除了值,i也要减1
/**
 * @param {number[]} nums
 * @return {number}
 */
var removeDuplicates = function (nums) {
    for (var i = 2; i < nums.length; i++) {
        if (nums[i] === nums[i - 2]) {
            nums.splice(i,1)
            i--
        } 
    }
    return nums.length
};