Fork me on GitHub

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 }

 

posted on 2023-04-08 10:05  Co3y  阅读(32)  评论(0编辑  收藏  举报

导航