删除排序数组中的重复项
题目描述:
给你一个 非严格递增排列 的数组 nums ,请你 原地 删除重复出现的元素,使每个元素 只出现一次 ,返回删除后数组的新长度。元素的 相对顺序 应该保持 一致 。然后返回 nums 中唯一元素的个数。
注意:
更改数组 nums ,使 nums 的前 k 个元素包含唯一元素,并按照它们最初在 nums 中出现的顺序排列。nums 的其余元素与 nums 的大小不重要。
返回 k 。
输入输出示例:
输入: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 。不需要考虑数组中超出新长度后面的元素。
解决方案主要为快慢双指针
方式一:简单实现方式
算法思想:设置两个指针fast和slow,fast指向要进行比较的元素,slow指向要处理的元素,每次比较两个元素的值是否相同,如果不相同,将fast指针的值赋给slow,如果相同,fast继续向下寻找不相同元素。
实现代码:
class Solution {
public int removeDuplicates(int[] nums) {
int fast=0;
int slow=0;
while(fast<nums.length){
if(nums[slow]==nums[fast]){
fast++;//相同,fast继续向下寻找不相同元素。
}else{
slow++;
nums[slow]=nums[fast];//不相同,将fast指针的值赋给slow
}
}
return slow+1;
}
}
方式二:双指针
算法思想:
数组有序,元素大小有序
由于给定的数组 nums 是有序的,
因此对于任意 i
则对任意 i≤k≤j,必有 nums[i]=nums[k]=nums[j],
即相等的元素在数组中的下标一定是连续的。利用数组有序的特点,可以通过双指针的方法删除重复元素。
当数组 nums 的长度大于 0 时,数组中至少包含一个元素,在删除重复元素之后也至少剩下一个元素,只有数组元素个数超过两个时,才会考虑元素重复的问题,因此 nums[0] 保持原状即可,从下标 1 开始删除重复元素。
定义两个指针 fast 和 slow 分别为快指针和慢指针,快指针表示遍历数组到达的下标位置,慢指针表示下一个要处理的下标位置,初始时两个指针都指向下标 1。
假设数组 nums 的长度为 n。将快指针 fast 依次遍历从 1 到 n−1 的每个位置,对于每个位置,如果 nums[fast]!=nums[fast−1],说明 nums[fast] 和之前的元素都不同,因此将 nums[fast] 的值复制到 nums[slow],然后将 slow 的值加 1,即指向下一个位置。
注意:如果数组 nums 的长度为 0,则数组不包含任何元素,因此返回 0。
实现代码:
class Solution {
public int removeDuplicates(int[] nums) {
int n = nums.length;
if (n == 0) {//严谨性判断
return 0;
}
int fast = 1, slow = 1;
while (fast < n) {
if (nums[fast] != nums[fast - 1]) {//如果快指针和上一个的值不相同,就是遇到了不同元素
nums[slow] = nums[fast];//fast的值赋给slow
++slow;
}
++fast;//如果相同,则继续遍历,直到遇到下一个不相同元素为止
}
return slow;
}
}
复杂度分析
时间复杂度:O(n),
其中 n 是数组的长度。快指针和慢指针最多各移动 n 次。
空间复杂度:O(1)。
只需要使用常数的额外空间。
删除数组的重复元素 进阶版
题目描述:
给你一个有序数组 nums ,请你 原地 删除重复出现的元素,使得出现次数超过两次的元素只出现两次 ,返回删除后数组的新长度。
不要使用额外的数组空间,你必须在 原地 修改输入数组 并在使用 O(1) 额外空间的条件下完成。
输入输出示例:
输入:nums = [1,1,1,2,2,3]
输出:5, nums = [1,1,2,2,3]
解释:函数应返回新长度 length = 5, 并且原数组的前五个元素被修改为 1, 1, 2, 2, 3。 不需要考虑数组中超出新长度后面的元素。
解决方案主要为快慢双指针
方式:快慢双指针
算法思想:
定义两个指针 slow 和 fast 分别为慢指针和快指针,
其中慢指针表示处理出的数组的长度,指向要保留的元素,
快指针表示已经比较过的数组的长度,指向要比较的元素
即 nums[fast] 表示待检查的第一个元素,nums[slow−1] 为上一个应该被保留的元素所移动到的指定位置。
1.数组的前两个数必然可以被保留,我们直接将双指针的初始值设为 2 即可。
2.因为本题要求相同元素最多出现两次而非一次,
所以我们需要检查上上个应该被保留的元素 nums[slow−2] 是否和当前待检查元素 nums[fast] 相同。
当且仅当 nums[slow−2]=nums[fast] 时,说明保留的元素中已经有两个了,
当前待检查元素 nums[fast] 不应该被保留。
3.最后,slow 即为处理好的数组的长度,返回slow的值。
注意:如果数组 nums 的长度不超过2,则数组中的全部元素都满足题目要求,因此返回数组长度。
实现代码
class Solution {
public int removeDuplicates(int[] nums) {
int n = nums.length;
if (n <= 2) {
return n;
}
int slow = 2, fast = 2;
while (fast < n) {
if (nums[slow - 2] != nums[fast]) {
nums[slow] = nums[fast];
++slow;
}
++fast;
}
return slow;
}
}
欢迎大家点赞,评论,加关注呦!!