26. 删除有序数组中的重复项 & 80. 删除有序数组中的重复项 II
力扣题目链接(26)
给你一个 升序排列 的数组 nums
,请你 原地 删除重复出现的元素,使每个元素 只出现一次 ,返回删除后数组的新长度。元素的 相对顺序 应该保持 一致 。
由于在某些语言中不能改变数组的长度,所以必须将结果放在数组nums的第一部分。更规范地说,如果在删除重复项之后有 k
个元素,那么 nums
的前 k
个元素应该保存最终结果。
将最终结果插入 nums
的前 k
个位置后返回 k
。
不要使用额外的空间,你必须在 原地 修改输入数组 并在使用 O(1) 额外空间的条件下完成。
示例 1:
输入:nums = [1,1,2] 输出:2, nums = [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] 解释:函数应该返回新的长度 5 , 并且原数组 nums 的前五个元素被修改为 0, 1, 2, 3, 4 。不需要考虑数组中超出新长度后面的元素。
提示:
1 <= nums.length <= 3 * 10^4
-10^4 <= nums[i] <= 10^4
nums
已按 升序 排列
解法一:
1 class Solution { 2 public int removeDuplicates(int[] nums) { 3 if (nums.length == 0) { 4 return 0; 5 } 6 int slow = 0, fast = 0; 7 while (fast < nums.length) { 8 if (nums[fast] != nums[slow]) { 9 slow++; 10 // 维护 nums[0..slow] 无重复 11 nums[slow] = nums[fast]; 12 } 13 fast++; 14 } 15 // 数组长度为索引 + 1 16 return slow + 1; 17 } 18 }
解法二(删除有序数组中的重复项的通用解法,26题可以转化为保留1位,80题可以转化为保留2位,类似的可以保留K位):
通用模板:
1 class Solution { 2 public int removeDuplicates(int[] nums, int k) { 3 int idx = 0; 4 for (int num : nums) { 5 if (idx < k || num != nums[idx - k]) 6 nums[idx++] = num; 7 } 8 return idx; 9 } 10 }
两个性质:
1.由于是保留 k 个相同数字,对于前 k 个数字,我们可以直接保留。
2.对于后面的任意数字,能够保留的前提是:与当前写入的位置前面的第 k 个元素进行比较,不相同则保留。
举个🌰,我们令 k=1,假设有样例:[3,3,3,3,4,4,4,5,5,5]
设定变量 idx,指向待插入位置。idx 初始值为 0,目标数组为 []
首先我们先让第 1 位直接保留(性质 1)。idx 变为 1,目标数组为 [3]
继续往后遍历,能够保留的前提是与 idx 的前面 1 位元素不同(性质 2),因此我们会跳过剩余的 3,将第一个 4 追加进去。idx 变为 2,目标数组为 [3,4]
继续这个过程,跳过剩余的 4,将第一个 5 追加进去。idx 变为 3,目标数组为 [3,4,5]
当整个数组被扫描完,最终我们得到了目标数组 [3,4,5] 和 答案 idx 为 3。
1 class Solution { 2 public int removeDuplicates(int[] nums) { 3 int idx = 0; 4 for (int num : nums) { 5 if (idx < 1 || num != nums[idx - 1]) 6 nums[idx++] = num; 7 } 8 return idx; 9 } 10 }
故可以完成80题。
力扣题目链接(80)
给你一个有序数组 nums
,请你 原地 删除重复出现的元素,使得出现次数超过两次的元素只出现两次 ,返回删除后数组的新长度。
不要使用额外的数组空间,你必须在 原地 修改输入数组 并在使用 O(1) 额外空间的条件下完成。
示例 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 * 10^4
-10^4 <= nums[i] <= 10^4
nums
已按升序排列
1 class Solution { 2 public int removeDuplicates(int[] nums) { 3 int idx = 0; 4 for (int num : nums) { 5 if (idx < 2 || num != nums[idx - 2]) 6 nums[idx++] = num; 7 } 8 return idx; 9 } 10 }