返回

升级你的前端算法技能:面试必刷题系列 33

前端

各位前端工程师们,准备好了迎接前端算法面试的挑战了吗?在这个系列文章中,我们将深入探讨一系列必刷题,帮助你提高解决算法问题的水平。今天,我们来到第 33 题:57. 删除有序数组中的重复项 II

问题

给你一个有序数组 nums,请你原地删除重复出现的元素,使每个元素最多出现两次,返回删除后数组的新长度。不要使用额外的数组空间,你必须在原地修改输入数组以满足要求。

示例 1:

输入:nums = [1,1,1,2,2,3]
输出:5
解释:删除重复项后,数组变为 [1,1,2,2,3]

示例 2:

输入:nums = [0,0,1,1,1,1,2,3,3]
输出:7
解释:删除重复项后,数组变为 [0,0,1,1,2,3,3]。

算法思路

这道题要求我们原地删除有序数组中重复出现的元素,但每个元素最多可以出现两次。我们首先介绍一个朴素的解法,然后介绍一种更优化的解法。

朴素解法:双指针法

该方法使用两个指针 ij 来遍历数组。指针 i 指向当前正在考虑的元素,而指针 j 指向下一个不同的元素。

  • nums[i]nums[j] 相等时,我们继续向右移动指针 j,直到找到下一个与 nums[i] 不同的元素。
  • nums[i]nums[j] 不相等时,我们把 nums[i + 1] 的值更新为 nums[j] 的值,并递增 ij

这种方法的时间复杂度为 O(n^2),其中 n 是数组的长度。虽然朴素,但它很容易理解和实现。

优化解法:双指针法

我们可以优化双指针法,将时间复杂度降至 O(n)。

  • 使用一个变量 count 来记录当前元素连续出现的次数。
  • nums[i]nums[i + 1] 相等时,我们递增 count
  • nums[i]nums[i + 1] 不相等时,我们更新 nums[j] 的值为 nums[i],并将 count 重置为 1。
  • 递增指针 j

这种优化后的解法避免了不必要的遍历,提高了算法的效率。

示例代码(C++)

class Solution {
public:
    int removeDuplicates(vector<int>& nums) {
        if (nums.empty()) {
            return 0;
        }
        int j = 0, count = 1;
        for (int i = 1; i < nums.size(); i++) {
            if (nums[i] == nums[i - 1]) {
                count++;
            } else {
                nums[j++] = nums[i - 1];
                count = 1;
            }
            if (count <= 2) {
                nums[j++] = nums[i];
            }
        }
        return j;
    }
};

结论

通过解决这道题,我们加深了对有序数组中删除重复项算法的理解。我们介绍了朴素的双指针法和优化的双指针法,并提供了详细的示例代码。掌握这些算法对于前端工程师准备算法面试和提高算法技能至关重要。请继续关注我们的系列文章,我们将探索更多前端算法面试必刷题,助你成为更出色的工程师!