leetcode初级算法题解Javascript - 26. 删除有序数组中的重复项

25 阅读3分钟

题目 26. 删除有序数组中的重复项

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

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

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

示例

输入:nums = [1,1,2]

输出:2, nums = [1,2,_]

解释:函数应该返回新的长度 2 ,并且原数组 nums 的前两个元素被修改为 1, 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 。不需要考虑数组中超出新长度后面的元素。

根据题意可知,函数需要满足以下两个条件:

  • 返回数组中唯一元素的数量k
  • 原地修改数组nums,保证数组前k项为唯一元素的集合,且不改变元素的相对顺序

题解1:

一开始我没有理解到数组是 非严格递增排列 这个特性,所以采用了先对数组去重,再将去重后留下的元素挪到数组左侧的做法。

  • 首先遍历数组,借助Map去重,将重复元素标记为 _
  • 双指针遍历去重后的nums: i 寻找可填入元素的位置,即当前元素是 _;j寻找非重复元素即数字

image.png

/**
 * @param {number[]} nums
 * @return {number}
 */
var removeDuplicates = function(nums) {
    let map = new Map()
    for(let i =0; i< nums.length; i++) {
        // map中有这个元素,则认为是重复出现 标记为 _
        if(map.has(nums[i])) {
            nums[i] = '_'
        } else {
        // map中没有则认为是唯一元素,存入map中
            map.set(nums[i])
        }
    }
   let i = 0
   let j = 1
   while(i < nums.length && j < nums.length) {
   // 当 i 位置的元素为 _, j 位置的元素为数字时,将 nums[j]的值赋值给nums[i]
       if(nums[i] == '_' && nums[j] != '_') {
           nums[i] = nums[j]
           nums[j] = '_'
           i++ 
           j++
       } 
       // 当前位置不是_,则不是可替换位置,i++
       if(nums[i] != '_') {
           i++ 
       } 
       // nums[j] == '_'当前位置不是有效数值 或 j<=i时, j++
       if(nums[j] == '_' || j <= i) {
           j++

       }
   }
   // map.size就是k
   return map.size
};

image.png

题解2

数组nums为非严格递增排列,即数组是有序的,那么重复的元素一定是相邻的;那么就可以不进行去重操作,只将数组中不重复的元素移到数组的左侧即可

依然采用双指针的做法:

  • 设置指针 i, j。i表示,i以及之前的元素都是不重复的;j指针始终比i指针快,来寻找下一个不重复元素;
  • 比较i 和 j 位置上的元素是否相等: 如果nums[i] == nums[j],表示元素重复,j++继续寻找不重复的元素;如果nums[i] != nums[j]则i位置更新向后移动i++且nums[i]保存nums[j], j指针更新

输入:nums = [0,0,1,1,1,2,2,3,3,4]

输出:5, nums = [0,1,2,3,4]

遍历过程如下:

image.png

image.png

image.png

/** 
* @param {number[]} nums 
* @return {number} 
*/ 
var removeDuplicates = function(nums) { 
    let i = 0
    let j = 1 
    while(i < nums.length && j< nums.length) {
        if(nums[i] == nums[j]) {
            j++
        } else { 
            i++ 
            nums[i] = nums[j] 
            j++ 
        } 
     } 
   return i + 1 
  };

代码如下:

/**
 * @param {number[]} nums
 * @return {number}
 */
var removeDuplicates = function(nums) {
    let i = 0
    let j = 1
    while(i < nums.length && j< nums.length) {
        if(nums[i] == nums[j]) {
            j++
        } else {
            i++
            nums[i] = nums[j]
            j++
        }
    }
    return i + 1

};

image.png

代码优化: 分析上述代码可以看到,不论if条件是否满足j指针都需要更新,所以可以修改一下判断条件,优化一下j指针的更新

/**
 * @param {number[]} nums
 * @return {number}
 */
var removeDuplicates = function(nums) {
    let i = 0
    let j = 1 
    while(i < nums.length && j< nums.length) {
        if(nums[i] != nums[j]) {
            i++ 
            nums[i] = nums[j] 
        }
        j++ 
     } 
   return i + 1 

};

image.png