题目难度:简单
默认优化目标:最小化平均时间复杂度。
Python默认为Python3。
1 题目描述
给你一个 非严格递增排列 的数组 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:
输入: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 <= nums.length <= 3 * 104
-
-104 <= nums[i] <= 104
-
nums
已按 非严格递增 排列
2 题目解析
输入是一个 非严格递增排列 的数组 nums
,输出是nums
中唯一元素的个数k
以及这些元素相对顺序不变的组成的数组nums
。
与27移除元素不同,27中是给你要删除的值val
,而本题是要删除数组中重复的元素。就像所给示例中展示的。
题目描述中有这么一句话,"nums
的其余元素与 nums
的大小不重要",这就意味着我们只要保证nums
的前 k
个元素包含唯一元素,而不需要真的从数组中将这些重复元素删除。
同时,由于输入的是非严格递增排列 的数组,相对顺序不变的意思就是升序排序。由于已经保证了非严格递增排列,因此排序操作也是不需要的。
综上,这道题只涉及交换操作。双指针应该是第一时间能想到的方法。
3 算法原理及程序实现
3.1 双指针
由于输出的要求是保证nums
的前 k
个元素包含唯一元素,所以两个指针都指向头节点。一个由于遍历数组,一个用于定位非重复元素的位置。如果元素不重复,就用当前元素去替换非重复元素后面的那一个元素值。
记定位非重复元素的位置的指针为left
,遍历数组的指针为right
。right
从数组下标位置1
开始到n-1
结束,left
从0
开始到n-2
结束,n
为nums
的长度。right
是连续的,即在大循环当中+1
,因为是遍历数组。left则是跳跃的,只有找到非重复元素才改变指向。要注意的是,left指向的是非重复元素的后一个位置,因此left
最多取n-2
。如果到n-1
,会数组越界。
用这种方法要考虑两个特例,一个是空数组输入,另一个是数组长度为1。空数组直接返回0
。长度为一的数组,元素必不重复,不用对数组进行操作,直接返回1
即可。考虑到这种情况在测试用例中的占比必然是少数,因此判断条件先判断n>=2
的情况,再是n==1
,最后!n
,即n==0
,以提高平均运行速度。
平均实践复杂度为O(n),平均空间复杂度为O(1)。
C++代码实现
class Solution { public: int removeDuplicates(vector<int>& nums) { int left=0; int n=nums.size(); int k=1;//初始长度为1 if(n>=2){ for(int right=1;right<n;right++){ if(nums[left]!=nums[right]){ nums[++left]=nums[right];//left先后移一位再改变指向nums元素的值 k++; } } }else if(n==1){ return k; } else{ return 0; } return k; } };
Python代码实现
class Solution: def removeDuplicates(self, nums: List[int]) -> int: left,right=0,1 k=1 n=len(nums) if n>=2: while right<n: if nums[left]!=nums[right]: left+=1 nums[left]=nums[right] k+=1 right+=1 elif n==1: return k else: return 0 return k
有关++left和left++的区别可以看每日一个小知识——P++和++P的区别。