超詳細講解:leetcode-0026-RemoveDuplicatesFromSortedArray(刪除排序陣列中的重複項)
阿新 • • 發佈:2021-01-12
技術標籤:leetcodepythonleetcodepython指標
文章目錄
1. 題目地址
2. 題目描述
- 英文描述
Given a sorted array nums, remove the duplicates in-place such that each element appears only once and returns the new length. Do not allocate extra space for another array, you must do this by modifying the input array in-place with O(1) extra memory. Clarification: Confused why the returned value is an integer but your answer is an array? Note that the input array is passed in by reference, which means a modification to the input array will be known to the caller as well. Internally you can think of this: // nums is passed in by reference. (i.e., without making a copy) int len = removeDuplicates(nums); // any modification to nums in your function would be known by the caller. // using the length returned by your function, it prints the first len elements. for (int i = 0; i < len; i++) { print(nums[i]); } Example 1: Input: nums = [1,1,2] Output: 2, nums = [1,2] Explanation: Your function should return length = 2, with the first two elements of nums being 1 and 2 respectively. It doesn't matter what you leave beyond the returned length. Example 2: Input: nums = [0,0,1,1,1,2,2,3,3,4] Output: 5, nums = [0,1,2,3,4] Explanation: Your function should return length = 5, with the first five elements of nums being modified to 0, 1, 2, 3, and 4 respectively. It doesn't matter what values are set beyond the returned length. Constraints: 0 <= nums.length <= 3 * 104 -104 <= nums[i] <= 104 nums is sorted in ascending order.
- 中文描述
給定一個排序陣列,你需要在 原地 刪除重複出現的元素,使得每個元素只出現一次,返回移除後陣列的新長度。 不要使用額外的陣列空間,你必須在 原地 修改輸入陣列,並在使用 O(1) 額外空間的條件下完成。 示例 1: 給定陣列 nums = [1,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。 你不需要考慮陣列中超出新長度後面的元素。 說明: 為什麼返回數值是整數,但輸出的答案是陣列呢? 請注意,輸入陣列是以「引用」方式傳遞的,這意味著在函式裡修改輸入陣列對於呼叫者是可見的。 你可以想象內部操作如下: // nums 是以“引用”方式傳遞的。也就是說,不對實參做任何拷貝 int len = removeDuplicates(nums); // 在函式裡修改輸入陣列對於呼叫者是可見的。 // 根據你的函式返回的長度, 它會打印出陣列中該長度範圍內的所有元素。 for (int i = 0; i < len; i++) { print(nums[i]); }
3. 解題思路
- 注意題目的關鍵點有4個:
(1)排序陣列:輸入陣列是個有序陣列,相同的重複元素是出現在一起的。
(2)原地刪除重複項:說明是需要將後面的元素覆蓋在需要刪除的重複元素上,不申請新陣列。
(3)不使用額外空間:肯定不能使用先統計每個元素出現的個數,再重新生成新陣列的方法了。
(4)最後需要返回刪除重複項後的新陣列的長度。 - 解題重點:雙指標
(1)採用快慢雙指標:使用快慢指標來記錄遍歷的下標。
(2)開始時這兩個指標都指向第1個數字。
(3)如果快慢兩個指標所指的數字相同,則快指標向前走一步。
(4)如果快慢兩個指標所指的數字不同,則兩個指標都向前走一步(慢指標往前走一步,快指標所指的值賦給慢指標,同時快指標也往前走一步),這一步是實現刪除重複元素的操作。
(6)時間複雜度:O(n)
(7)空間複雜度:O(1)
解題步驟解析:
最開始的時候兩個指標都指向第1個數字,所以快指標就開始向前走一步了。
這個時候慢指標指向第1個數字,快指標指向第2個數字,如果這兩個數字相同,那麼快指標繼續往前走,快指標指向的就是第3個數字,慢指標還指在第1個數字上。
此時再次比較快慢指標所指的元素是否相同:
如果相同,說明前3個數字都是相同的,快指標就繼續往前走。
如果不同,那麼說明第1個數字和第2個數字是相同的,第3個數字是不同的,所以此時:(1)慢指標往前走一步,(2)快指標所指的值賦給慢指標,即將第3個位置上的元素挪到第2個位置,去除了重複項。(3)快指標往前走一步,繼續遍歷下一個元素。
再次比較快慢指標所指元素是否相同,重複之間的步驟。
我們用更極端的一種情況來分析一下所指元素不同時的那一步操作:
如果每個數字都不同,那麼最開始時兩個指標都指向第1個數字,快指標開始向前走一步。此時快慢指標所指的元素不相同:(1)慢指標往前走一步,(2)快指標和慢指標此時又指向了相同的位置,快指標所指的值賦給慢指標,其實是同一個值的賦值操作,快指標往前走一步。
再次比較快慢指標所指元素是否相同,重複之前的步驟。
當快指標走完整個陣列後,慢指標所在位置其實就是最終去重後陣列的末尾元素的位置。所以此時慢指標當前的座標加 1 就是陣列中不同數字的個數。
4. 解題關鍵
- 要想到快慢雙指標的操作
- 第1步:快慢兩個指標同時指向第1個元素。
- 第2步:若快慢兩個指標所指的數字相同,則快指標向前走一步。
- 第3步:若快慢兩個指標所指的數字不同,則兩個指標都向前走一步(慢指標往前走一步,快指標所指的值賦給慢指標所指位置,同時快指標也往前走一步)。
- 第4步:當快指標走完整個陣列後,慢指標當前的座標加 1 就是陣列中不同數字的個數。
- 要點
- 輸入是排序陣列
- 原地刪除重複項
- 不使用額外空間
- 注意nums為空時的邊界條件
- 複雜度
- 時間複雜度:O(n)
- 空間複雜度:O(1)
5. 示例程式碼
python
# coding:utf-8
'''
# @Method:快慢指標
# @Author: wlhr62
'''
import os
class Solution:
def removeDuplicates(self, nums: List[int]) -> int:
if nums:
slow = 0
fast = 0
while(fast != len(nums)):
if nums[fast] == nums[slow]:
fast += 1
else:
slow += 1
nums[slow] = nums[fast]
fast += 1
return slow+1
else:
return 0
if __name__ == "__main__":
nums = [1, 1, 2]
A = Solution()
res = A.removeDuplicates(nums)
print(res)
在leetcode上AC的結果: