原文链接: https://leetcode-cn.com/problems/remove-duplicates-from-sorted-array-ii
英文原文
Given an integer array nums
sorted in non-decreasing order, remove some duplicates in-place such that each unique element appears at most twice. The relative order of the elements should be kept the same.
Since it is impossible to change the length of the array in some languages, you must instead have the result be placed in the first part of the array nums
. More formally, if there are k
elements after removing the duplicates, then the first k
elements of nums
should hold the final result. It does not matter what you leave beyond the first k
elements.
Return k
after placing the final result in the first k
slots of nums
.
Do not allocate extra space for another array. You must do this by modifying the input array in-place with O(1) extra memory.
Custom Judge:
The judge will test your solution with the following code:
int[] nums = [...]; // Input array int[] expectedNums = [...]; // The expected answer with correct length int k = removeDuplicates(nums); // Calls your implementation assert k == expectedNums.length; for (int i = 0; i < k; i++) { assert nums[i] == expectedNums[i]; }
If all assertions pass, then your solution will be accepted.
Example 1:
Input: nums = [1,1,1,2,2,3] Output: 5, nums = [1,1,2,2,3,_] Explanation: Your function should return k = 5, with the first five elements of nums being 1, 1, 2, 2 and 3 respectively. It does not matter what you leave beyond the returned k (hence they are underscores).
Example 2:
Input: nums = [0,0,1,1,1,1,2,3,3] Output: 7, nums = [0,0,1,1,2,3,3,_,_] Explanation: Your function should return k = 7, with the first seven elements of nums being 0, 0, 1, 1, 2, 3 and 3 respectively. It does not matter what you leave beyond the returned k (hence they are underscores).
Constraints:
1 <= nums.length <= 3 * 104
-104 <= nums[i] <= 104
nums
is sorted in non-decreasing order.
中文题目
给你一个有序数组 nums
,请你 原地 删除重复出现的元素,使每个元素 最多出现两次 ,返回删除后数组的新长度。
不要使用额外的数组空间,你必须在 原地 修改输入数组 并在使用 O(1) 额外空间的条件下完成。
说明:
为什么返回数值是整数,但输出的答案是数组呢?
请注意,输入数组是以「引用」方式传递的,这意味着在函数里修改输入数组对于调用者是可见的。
你可以想象内部操作如下:
// nums 是以“引用”方式传递的。也就是说,不对实参做任何拷贝 int len = removeDuplicates(nums); // 在函数里修改输入数组对于调用者是可见的。 // 根据你的函数返回的长度, 它会打印出数组中 该长度范围内 的所有元素。 for (int i = 0; i < len; i++) { print(nums[i]); }
示例 1:
输入:nums = [1,1,1,2,2,3] 输出:5, nums = [1,1,2,2,3] 解释:函数应返回新长度 length =5
, 并且原数组的前五个元素被修改为1, 1, 2, 2,
3 。 不需要考虑数组中超出新长度后面的元素。
示例 2:
输入:nums = [0,0,1,1,1,1,2,3,3] 输出:7, nums = [0,0,1,1,2,3,3] 解释:函数应返回新长度 length =7
, 并且原数组的前五个元素被修改为0
, 0, 1, 1, 2, 3, 3 。 不需要考虑数组中超出新长度后面的元素。
提示:
1 <= nums.length <= 3 * 104
-104 <= nums[i] <= 104
nums
已按升序排列
通过代码
高赞题解
通用解法
为了让解法更具有一般性,我们将原问题的「保留 2 位」修改为「保留 k 位」。
对于此类问题,我们应该进行如下考虑:
- 由于是保留
k
个相同数字,对于前k
个数字,我们可以直接保留 - 对于后面的任意数字,能够保留的前提是:与当前写入的位置前面的第
k
个元素进行比较,不相同则保留
举个🌰,我们令 k=2
,假设有如下样例
[1,1,1,1,1,1,2,2,2,2,2,2,3]
- 首先我们先让前 2 位直接保留,得到 1,1
- 对后面的每一位进行继续遍历,能够保留的前提是与当前位置的前面
k
个元素不同(答案中的第一个 1),因此我们会跳过剩余的 1,将第一个 2 追加,得到 1,1,2 - 继续这个过程,这时候是和答案中的第 2 个 1 进行对比,因此可以得到 1,1,2,2
- 这时候和答案中的第 1 个 2 比较,只有与其不同的元素能追加到答案,因此剩余的 2 被跳过,3 被追加到答案:1,1,2,2,3
代码(感谢 @Qian 、@宫水三叶的小迷妹 和 @007 三位同学提供的其他语言版本):
class Solution {
public int removeDuplicates(int[] nums) {
return process(nums, 2);
}
int process(int[] nums, int k) {
int u = 0;
for (int x : nums) {
if (u < k || nums[u - k] != x) nums[u++] = x;
}
return u;
}
}
class Solution {
public:
int work(vector<int>& nums, int k) {
int len = 0;
for(auto num : nums)
if(len < k || nums[len-k] != num)
nums[len++] = num;
return len;
}
int removeDuplicates(vector<int>& nums) {
return work(nums, 2);
}
};
class Solution:
def removeDuplicates(self, nums: List[int]) -> int:
def solve(k):
u = 0
for x in nums:
if u < k or nums[u - k] != x:
nums[u] = x
u += 1
return u
return solve(2)
func removeDuplicates(nums []int) int {
var process func(k int) int
process = func(k int) int {
u := 0
for _, v := range nums {
if u < k || nums[u-k] != v {
nums[u] = v
u++
}
}
return u
}
return process(2)
}
- 时间复杂度:$O(n)$
- 空间复杂度:$O(1)$
其他
这是一种针对「数据有序,相同元素保留 k
位」问题更加本质的解法,该解法是从性质出发提炼的,利用了「数组有序 & 保留逻辑」两大主要性质。
当你掌握这种通解之后,要解决 26. 删除有序数组中的重复项 ,只需要改上述代码一个数字即可(将相同数字保留 2 个修改为保留 1 个)。
这种通解最早我也在 【宫水三叶】「双指针」&「通用」解法 讲过。
最后
如果有帮助到你,请给题解点个赞和收藏,让更多的人看到 ~ (“▔□▔)/
也欢迎你 关注我(公主号后台回复「送书」即可参与长期看题解学算法送实体书活动)或 加入「组队打卡」小群 ,提供写「证明」&「思路」的高质量题解。
所有题解已经加入 刷题指南,欢迎 star 哦 ~
统计信息
通过次数 | 提交次数 | AC比率 |
---|---|---|
155802 | 252267 | 61.8% |
提交历史
提交时间 | 提交结果 | 执行时间 | 内存消耗 | 语言 |
---|
相似题目
题目 | 难度 |
---|---|
删除有序数组中的重复项 | 简单 |