【LeetCode.27】 移除元素

題目描述

給你一個數組 nums 和一個值 val,你需要 原地 移除所有數值等於 val 的元素,並返回移除後數組的新長度。

不要使用額外的數組空間,你必須僅使用 O(1) 額外空間並 原地 修改輸入數組。

元素的順序可以改變。你不需要考慮數組中超出新長度後面的元素。

示例 1:

給定 nums = [3,2,2,3], val = 3,
函數應該返回新的長度 2, 並且 nums 中的前兩個元素均爲 2。
你不需要考慮數組中超出新長度後面的元素。

示例 2:

給定 nums = [0,1,2,2,3,0,4,2], val = 2,
函數應該返回新的長度 5, 並且 nums 中的前五個元素爲 0, 1, 3, 0, 4。
注意這五個元素可爲任意順序。
你不需要考慮數組中超出新長度後面的元素。

理解題意

  • 原地修改數組,指的是直接對數組參數 取下標來修改數組元素,而不是通過將數組參數引用指向一個新的數組。
  • 返回值爲與val不等的元素個數。

解法——快慢指針

解法關鍵詞

  • 雙指針
  • 快慢指針
    在這裏插入圖片描述
  • 我們將算法結束後關心的前n個元素,稱爲壓實數組。因爲整個過程看起來就是在往左壓實。
  • compactIndex代表即將加入壓實數組的那個元素應該賦值的索引。所以初始時,compactIndex爲0,因爲初始時一個非val元素都沒有得到確認。
  • cursor即爲遍歷指針。
  • 當遍歷元素非val時,將其賦值給compactIndex位置,並compactIndex增加1.
  • 由於compactIndex剛好與壓實數組的長度一樣,所以函數返回compactIndex。
  • 圖中最後一步,壓實數組中兩個元素顏色不同,是因爲它們可能不相等,但都不是val。
class Solution:
    def removeElement(self, nums: List[int], val: int) -> int:
        compactIndex = 0
        for cursor in range(len(nums)):
            if nums[cursor] != val:
                nums[compactIndex] = nums[cursor]
                compactIndex += 1
        return compactIndex

解法——雙端指針

解法關鍵詞

  • 雙指針
  • 雙端指針

題目中提到了元素的順序可以修改,所以可以使用這種解法,時間複雜度一樣。
在這裏插入圖片描述

  • 之間的解法是通過一個指針來遍歷數組,現在則是通過兩端的指針來遍歷數組,通過待確認的元素納入兩個指針的範圍內。左指針往右移動,右指針往左移動。
  • 通過left指針來判斷壓實數組的末尾,因爲left總是指向 壓實數組最大索引+1。(最大索引+1 就是長度)
  • 如果數組都是val,那麼left不動,right一直移動;如果數組都非val,那麼right不動,left一直移動。
  • 當left元素非val時,說明它不是想要的,則可以被覆蓋,覆蓋的值則是right元素,並right指針減1。因爲下一次檢查還是從left檢查。
  • 當left元素爲val時,說明它是想要的,確認了一個壓實元素,則left指針移動。
  • 圖中可見,五個元素只循環了五次。
class Solution:
    def removeElement(self, nums, val):
        left = 0
        right = len(nums)-1

        while(left <= right):
            if nums[left] == val:
                nums[left] = nums[right]
                right -= 1
            else:
                left += 1
        return left
  • 因爲right指向最大元素所在索引,所以區間是一個[left, right]的左閉右閉區間(每次循環中,待確認的元素,就在這個區間之中),所以最後一次循環肯定是left = right的情況。所以循環條件爲left <= right
    在這裏插入圖片描述
class Solution:
    def removeElement(self, nums, val):
        left = 0
        right = len(nums)

        while(left < right):
            if nums[left] == val:
                right -= 1
                nums[left] = nums[right]
            else:
                left += 1
        return left
  • 因爲right指向最大元素所在索引+1,所以區間是一個[left, right)的左閉右開區間(每次循環中,待確認的元素,就在這個區間之中),所以最後一次循環肯定是left < right的情況。那麼其實每次循環的條件都是left < right了,所以循環條件爲left < right
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章