算法:删除有序数组的重复项

📑 删除有序数组的重复项


题目描述

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

考虑 nums 的唯一元素的数量为 k ,你需要做以下事情:

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

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

通俗解释

想象一下你在搬家,需要整理书架上的书。书架上的书已经按作者姓氏的字母顺序排列好了,但有些作者有多本书(重复项)。

你的任务是:

  1. 把每个作者的第一本书保留在书架上
  2. 把重复的作者书籍放到箱子里(不需要管)
  3. 最后书架上的书都是不重复的,且保持原来的顺序

具体操作:

  • 你从书架的第二本书开始检查(第一本肯定要保留)
  • 如果当前书和前面保留的书是同一个作者,就把它放到箱子里
  • 如果当前书是新的作者,就把它放到保留区的下一位置
  • 最后数一数保留区有多少本书

这就是 双指针算法 的生动比喻!


for循环解法

java 复制代码
class Solution {
    public int removeDuplicates(int[] nums) {
        // 边界情况:如果数组为空或者只有一个元素,直接返回长度即可
        if (nums == null || nums.length == 0) {
            return 0;
        }
        
        // 1. 定义慢指针 (slow)
        // 它的含义是:[0, slow] 闭区间内的元素都是不重复的、整理好的
        // 初始时,第0个位置的元素肯定要保留,所以 slow 从 0 开始
        int slow = 0;

        // 2. 定义快指针 (fast),开始遍历
        // 从索引 1 开始,因为索引 0 的元素我们已经默认放进去了
        for (int fast = 1; fast < nums.length; fast++) {
            
            // 3. 核心逻辑:对比
            // 如果快指针指向的数,和慢指针指向的数不一样
            // 说明遇到了一个"新数字"
            if (nums[fast] != nums[slow]) {
                
                // 4. 慢指针先向右挪一步,腾出位置放新书
                slow++;
                
                // 5. 把快指针找到的新书,放到慢指针的位置
                // (其实这里可以直接赋值,因为题目只要求前k个有序且不重复)
                nums[slow] = nums[fast];
            }
            // 如果一样,什么也不做,快指针继续跑,相当于把重复的书扔进了垃圾桶
        }

        // 6. 返回新数组的长度
        // 因为索引是从0开始的,所以长度要 +1
        return slow + 1;
    }
}

while循环解法

这是我自己的写法,也通过了

java 复制代码
	  public int removeDuplicates(int[] nums) {
		  int slow = 0;//慢指针
		  int fast = slow+1;//快指针
		  int result = 1;
		  while(j<nums.length) {
			  if(nums[slow]!=nums[fast]) {
				  //根据题意:result的当前个数就是新数组的下标
                  nums[result]=nums[fast];
                  //计数+1
				  result++;
                  //慢指针移到快指针的位置
				  slow= fast;
			  }
			  
			  fast++;
		  }
	     
		  return result;
	    }