题目描述
给定一个排序数组,你需要在 原地 删除重复出现的元素,使得每个元素只出现一次,返回移除后数组的新长度。
难度 简单
不要使用额外的数组空间,你必须在原地修改输入数组 并在使用 O(1) 额外空间的条件下完成。
示例1
给定数组 nums = [1,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。
你不需要考虑数组中超出新长度后面的元素
解题思路
由于数组是已经排序好的,那么重复的元素就一定是相邻的,原地修改数组的话,双指针是一个很好的方案。可以在遍历中,用两个指针p1 = 0, p1 = 1 指向数组,当 nums[p2] == nums[p1] 时,p2 右移, 直到nums[p2] !== nums[p1], 这时需要将 nums[p2] 赋值给 nums[p1 + 1]上, 重复以上过程,直到p2指向数组的末尾,p1则永远指向着已经处理完成的左半部分数组的最大下标, 那么p1 + 1 已经处理完成的左半部分数组的长度
实现代码
impl Solution {
pub fn remove_duplicates(nums: &mut Vec<i32>) -> i32 {
if nums.is_empty() {
return 0
}
let (mut p1, mut p2) = (0,1);
while p2 < nums.len() {
if nums[p2] == nums[p1] {
p2 +=1;
} else {
p1 += 1;
nums[p1] = nums[p2];
}
}
p1 as i32 + 1
}
}
总结
时间复杂度:O(2n)。// 至多是p1, p2完整的遍历2次数组
空间复杂度:O(1) 只是用2个额外变量存储下标。
双指针解法非常重要和有效, 这道题是LeetCode中leetbook初级算法的第一道题,之后的数组,字符串和链表相关问题都有双指针出现的机会。我个人的理解是,相当于使用p1标记已处理完成的前半个数组,使用p2去搜寻下一个需要增加的元素。