题目
给你一个升序排列的数组 nums,请你原地删除重复出现的元素,使每个元素只出现一次,返回删除后数组的新长度。元素的相对顺序应该保持一致 。
由于在某些语言中不能改变数组的长度,所以必须将结果放在数组nums的第一部分。更规范地说,如果在删除重复项之后有 k 个元素,那么 nums 的前 k 个元素应该保存最终结果。
将最终结果插入 nums 的前 k 个位置后返回 k 。
不要使用额外的空间,你必须在原地修改输入数组并在使用 O(1) 额外空间的条件下完成。
解法一
看到这种删除数组中元素的问题我们首先想到的是遍历数组,将要删除位置后面的元素前移覆盖。实现这种思想最直接的方法就是两重for循环嵌套,一层负责遍历,一层负责前移。
但是我们知道,一般算法的时间复杂度 >= O()就不太好了,而该算法的时间复杂度就是O(),那么是否有更优的算法呢?
class Solution {
public int removeDuplicates(int[] nums) {
int len = nums.length;
for(int i = 0;i < len - 1;i++){ //遍历数组
if(nums[i] == nums[i+1]){
for(int j = i+1;j < len - 1;j++){ //覆盖前移
nums[j] = nums[j+1];
}
len--; //数组长度-1
i--; //下一个元素继续与本元素比较,用i--抵消i++
}
}
return len;
}
}
解法二——双指针法
这里我不做过多解释,看LeeCode给出的官方动图解就一目了然了
删除排序数组中的重复项 - 删除有序数组中的重复项 - 力扣(LeetCode)
该方法处理只需要一个循环语句,所以复杂度仅仅为O(n),远小于我们的第一种方法!
class Solution {
public int removeDuplicates(int[] nums) {
int head = 1,tail = 0;
if(nums.length < 2)
return nums.length;
while(head < nums.length){
if(nums[head] != nums[tail]){
tail++;
nums[tail] = nums[head];
}
head++;
}
return tail+1; //因为对于tail指针是先移动再赋值,所以长度等于末尾值+1
}
}