算法:删除有序数组的重复项
📑 删除有序数组的重复项
- 题目描述
- 形象的比喻:搬家整理书架
- for循环解法
- while循环解法
题目描述
给你一个非严格递增排列的数组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循环解法
classSolution{publicintremoveDuplicates(int[]nums){// 边界情况:如果数组为空或者只有一个元素,直接返回长度即可if(nums==null||nums.length==0){return0;}// 1. 定义慢指针 (slow)// 它的含义是:[0, slow] 闭区间内的元素都是不重复的、整理好的// 初始时,第0个位置的元素肯定要保留,所以 slow 从 0 开始intslow=0;// 2. 定义快指针 (fast),开始遍历// 从索引 1 开始,因为索引 0 的元素我们已经默认放进去了for(intfast=1;fast<nums.length;fast++){// 3. 核心逻辑:对比// 如果快指针指向的数,和慢指针指向的数不一样// 说明遇到了一个"新数字"if(nums[fast]!=nums[slow]){// 4. 慢指针先向右挪一步,腾出位置放新书slow++;// 5. 把快指针找到的新书,放到慢指针的位置// (其实这里可以直接赋值,因为题目只要求前k个有序且不重复)nums[slow]=nums[fast];}// 如果一样,什么也不做,快指针继续跑,相当于把重复的书扔进了垃圾桶}// 6. 返回新数组的长度// 因为索引是从0开始的,所以长度要 +1returnslow+1;}}while循环解法
这是我自己的写法,也通过了
publicintremoveDuplicates(int[]nums){intslow=0;//慢指针intfast=slow+1;//快指针intresult=1;while(j<nums.length){if(nums[slow]!=nums[fast]){//根据题意:result的当前个数就是新数组的下标nums[result]=nums[fast];//计数+1result++;//慢指针移到快指针的位置slow=fast;}fast++;}returnresult;}