题目

给定一个增序排列数组 nums ,你需要在 原地 删除重复出现的元素,使得每个元素最多出现两次,返回移除后数组的新长度。
不要使用额外的数组空间,你必须在 原地 修改输入数组 并在使用 O(1) 额外空间的条件下完成。

思路-O(n^2)

删除排序数组中的重复项思路相似,加入计数器判断元素是否出现了2次。

  1. class Solution {
  2. public int removeDuplicates(int[] nums) {
  3. int count = 0; // 计数器
  4. int i = 0;
  5. int removed = 0;
  6. while (i + removed < nums.length - 1) {
  7. if (nums[i] != nums[i + 1]) { // 相邻数不一样,计数器清零
  8. i++;
  9. count = 0;
  10. } else {
  11. count++; // 相邻数一样,计数器+1
  12. if (count < 2) { // 已经出现次数小于2次,放过
  13. i++;
  14. } else { // 已经出现了2次,这次是第3次,删除
  15. removeOne(nums, i + 1);
  16. removed++;
  17. }
  18. }
  19. }
  20. return nums.length - removed;
  21. }
  22. public void removeOne(int[] nums, int i) {
  23. for (int k = i; k < nums.length - 1; k++) {
  24. nums[k] = nums[k + 1];
  25. }
  26. }
  27. }

思路-O(n)

示例: nums = [1, 2, 3, 4, 4, 4, 5]

slow和fast指针在遇到第三个4(也就是nums[5]) 之前, nums[slow] = nums[fast] 一直是无效的交换。因为fast和slow的值是相等的,nums[slow - 2] != nums[fast] 一直都是true,所以每次while loop的时候 slow和fast都会++,它们的初始值又都是2。

slow和fast指针在遇到第三个4(也就是nums[5]) 的时候,这时候就需要将nums[6]换到nums[5],也就是说,fast需要比slow快1个位置。if(nums[slow - 2] != nums[fast]) 不会运行,就使得fast++但是slow没有++。

总结一下:
如果 slow的第前两个数 不等于 fast的数:
情况一:slow的数 等于 fast的数
slow 和 fast 原地无效交换
slow++;fast++;
情况二:slow的数 不等于 fast的数
slow 和 fast 有效交换 (因为slow和fast指向的数不同)
slow++;fast++;
如果 slow的第前两个数 等于 fast的数:
此时说明slow位置需要被替换,替换的前提是fast要跑到slow的前面去,
所以fast++, slow原地不动

  1. class Solution {
  2. public int removeDuplicates(int[] nums) {
  3. if (nums.length <= 2) { // 长度小于3,不可能有重复项大于2次的元素,直接返回
  4. return nums.length;
  5. }
  6. int slow = 2;
  7. int fast = 2;
  8. while (fast < nums.length) {
  9. if (nums[slow - 2] != nums[fast]) {
  10. nums[slow] = nums[fast];
  11. slow++;
  12. }
  13. fast++;
  14. }
  15. return slow;
  16. }
  17. }