Leetcode 27:移除元素

題目

Given an array nums and a value val, remove all instances of that value in-place and return 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.
The order of elements can be changed. It doesn’t matter what you leave beyond the new length.

給定一個數組 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。

注意這五個元素可爲任意順序。

你不需要考慮數組中超出新長度後面的元素。

方法一、雙指針:

思路

既然問題要求我們就地刪除給定值的所有元素,我們就必須用O(1) 的額外空間來處理它。如何解決?我們可以保留兩個指針i 和j,其中 i是慢指針,j 是快指針。

算法

當 nums[j]與給定的值相等時,遞增 j以跳過該元素。只要 nums[j]!=val,我們就複製 nums[j] 到nums[i] 並同時遞增兩個索引。重複這一過程,直到 j到達數組的末尾,該數組的新長度爲 i。
該解法與 刪除排序數組中的重複項 的解法十分相似。

public int removeElement(int[] nums, int val) {
    int i = 0;
    for (int j = 0; j < nums.length; j++) {
        if (nums[j] != val) {
            nums[i] = nums[j];
            i++;
        }
    }
    return i;
}

複雜度分析

時間複雜度:O(n), 假設數組總共有 n 個元素,i 和 j至少遍歷 n步。
空間複雜度:O(1)。

方法二、雙指針 —— 當要刪除的元素很少時:

思路

現在考慮數組包含很少的要刪除的元素的情況。例如,nums=[1,2,3,5,4],var=4。之前的算法會對前四個元素做不必要的複製操作。另一個例子是 nums=[4,2,3,5,1],var=4。似乎沒有必要將[2,3,5,1] 這幾個元素左移一步,因爲問題描述中提到元素的順序可以更改。

算法

當我們遇到 nums[i] == val 時,我們可以將當前元素與最後一個元素進行交換,並釋放最後一個元素。這實際上使數組的大小減少了 1。

請注意,被交換的最後一個元素可能是您想要移除的值。但是不要擔心,在下一次迭代中,我們仍然會檢查這個元素。

public int removeElement(int[] nums, int val) {
    int i = 0;
    int n = nums.length;
    while (i < n) {
        if (nums[i] == val) {
            nums[i] = nums[n - 1];
            // reduce array size by one
            n--;
        } else {
            i++;
        }
    }
    return n;
}

複雜度分析

時間複雜度:O(n),i 和 n最多遍歷 n 步。在這個方法中,賦值操作的次數等於要刪除的元素的數量。因此,如果要移除的元素很少,效率會更高。
空間複雜度:O(1)。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章