O(1)空间复杂度下有序数组去重问题的排查与优化
解决有序数组原地去重的问题
你的代码在处理奇数次重复元素时失效,核心问题是:当你用pop(i)移除重复元素后,当前i位置被下一个元素填充,但你直接让i递增,跳过了对这个新元素的检查。比如处理[1,1,1]时,第一次pop后数组变成[1,1],i直接变成1,此时i == end,循环终止,剩下的重复元素没被处理。
下面是几种可行的解决技巧:
技巧1:修正现有代码的指针逻辑
把i的递增移到else分支里,只有当前元素和下一个元素不重复时,才让i递增。这样移除重复元素后,i留在原地,继续检查新的当前元素:
def removeDuplicates(nums): if not nums: return 0 i = 0 end = len(nums) - 1 while i != end: if nums[i] == nums[i+1]: nums.pop(i) end -= 1 else: i += 1 return len(nums)
测试输入[0,0,1,1,1,2,2,3,3,4],会得到去重后的数组[0,1,2,3,4],返回长度5,完全符合要求。
技巧2:双指针(快慢指针)法(最优解)
这是这类原地去重题的标准高效解法,时间复杂度O(n),空间复杂度O(1),比多次pop操作更高效(pop列表中间元素是O(n)时间,多次操作会拉高整体复杂度)。
思路:用慢指针slow标记去重后数组的最后位置,快指针fast遍历整个数组。当快指针遇到和慢指针不同的元素时,慢指针前进一位,把快指针的元素赋值过去:
def removeDuplicates(nums): if not nums: return 0 slow = 0 for fast in range(1, len(nums)): if nums[fast] != nums[slow]: slow += 1 nums[slow] = nums[fast] return slow + 1
这个方法不需要删除元素,只是覆盖前面的位置,完全符合“不创建新数组”的要求,不管重复次数是奇数还是偶数都能正确处理。
技巧3:反向遍历删除
从数组末尾开始遍历,删除元素时不会影响前面未遍历元素的索引,避免指针混乱:
def removeDuplicates(nums): for i in range(len(nums)-1, 0, -1): if nums[i] == nums[i-1]: nums.pop(i) return len(nums)
反向遍历的好处是,删除当前元素后,前面的元素索引不受影响,遍历过程不会遗漏任何重复情况,逻辑简单易懂。
内容的提问来源于stack exchange,提问作者Rhodey
相关产品推荐
相关产品推荐

