📑 删除有序数组的重复项
题目描述
给你一个 非严格递增排列 的数组 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 。不需要考虑数组中超出新长度后面的元素。
通俗解释
想象一下你在搬家,需要整理书架上的书。书架上的书已经按作者姓氏的字母顺序排列好了,但有些作者有多本书(重复项)。
你的任务是:
- 把每个作者的第一本书保留在书架上
- 把重复的作者书籍放到箱子里(不需要管)
- 最后书架上的书都是不重复的,且保持原来的顺序
具体操作:
- 你从书架的第二本书开始检查(第一本肯定要保留)
- 如果当前书和前面保留的书是同一个作者,就把它放到箱子里
- 如果当前书是新的作者,就把它放到保留区的下一位置
- 最后数一数保留区有多少本书
这就是 双指针算法 的生动比喻!
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;
}