leetcode打卡-0026删除数组中重复项
题目描述
给你一个有序数组nums,请你原地删除重复出现的元素,使每个元素只出现一次,返回删除后数组的新长度。
不要使用额外的数组空间,你必须在原地修改输入数组并在使用O(1)额外空间的条件下完成。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/remove-duplicates-from-sorted-array
解题思路
1. 双指针
按照正常思维思考这题,可以划分一个额外的临时数组tmp,从头遍历原始数组nums,不断地比较,将新元素放进tmp里,不过题目要求原地删除,所以需要简单修改一下,将新元素直接放到原始nums里去,占用以前元素的位置。
用一个慢指针slow指向有效数组的最后一个位置,用来记录不重复数组的尾部,用一个快指针fast顺序遍历数组。
当fast与slow所指的值不一致时,证明这是两个不重复元素,将slow后一位的值改为fast指向的值,slow前进一位,fast继续遍历即可,最后返回长度即为slow+1。
# Python实现
class Solution:
def removeDuplicates(self, nums: List[int]) -> int:
if nums == []:
return 0
i = 0
length = len(nums)
for j in range(1, length):
if nums[i] != nums[j]:
i += 1
nums[i] = nums[j]
return i + 1
顺便练习一下Rust
impl Solution {
pub fn remove_duplicates(nums: &mut Vec<i32>) -> i32 {
if nums.is_empty() {
return 0;
}
let mut i = 0;
for j in 1..nums.len() {
if nums[i] != nums[j] {
i += 1;
nums[i] = nums[j];
}
}
i as i32 + 1
}
}
2. 通用套路思维
如果将原问题的「最多保留1位」修改为「最多保留k位」,问题会更有通用性,例如leetcode第80题。
这个想法来自于宫水三叶的题解,很巧妙,此处参考引证一下。
- 由于是保留k个相同数字,对于前k个数字,我们可以直接保留。
- 对于后面的任意数字,能够保留的前提是:与当前写入的位置前面的第k个元素进行比较,不相同则保留。
第一条很好理解,因为这是有序数组,所以前k个元素里,每种数字都会符合不超过k个的条件;第二条,就是反向思考,一个数字与写入位置的第前k个元素对比,如果相同,证明写入位置之前已经写满了k个当前元素,那么写入位置就需要寻找一个新元素写入了,如果不同,就把当前元素复制过去补位。
所以,通用的Python实现代码如下:
def process(nums, k):
# idx记录最初的写入位置,直接保留了前k位
idx = k
# 从第k位往后遍历,判断是否满足上面的第二条推定
for x in nums[k:]:
if nums[idx-k] != x:
nums[idx] = x
idx += 1
return idx
总结
双指针的方法很容易想到,在处理字符串问题是比较常用,不过后面的通用解法,它是建立在“数组有序”且“保留逻辑”的基础上,可以作为解决这种字符串问题的套路尝试。