1. 程式人生 > >leetcode_陣列問題的雙指標思路

leetcode_陣列問題的雙指標思路

陣列操作問題:雙指標方法

  • 似乎要求掃描一遍的方法大多可以採用雙指標解決, 尤其是刪除陣列中某類不合法的資料
  • 要明確一點,區間 [0, k) 存放的是合法的資料, k指標所指位置的數值沒有任何意義,它是下一個合法資料要佔據的位置(要麼被下一個合法資料覆蓋,要麼和下一個合法資料交換位置)
  • i指標置於一個for迴圈中,用於從頭到位掃描陣列中的各個元素,根據具體條件找出合法的資料,佔據k指標所指位置.

 

283.零移動

給定一個數組 nums,編寫一個函式將所有 0 移動到陣列的末尾,同時保持非零元素的相對順序。

示例:

輸入: [0,1,0,3,12]
輸出: [1,3,12,0,0]

說明:

  1. 必須在原陣列上操作,不能拷貝額外的陣列。
  2. 儘量減少操作次數。

方法1: 利用一個額外的輔助陣列.時間複雜度O(n);  空間複雜度O(n)

class Solution {
    public void moveZeroes(int[] nums) {
        ArrayList<Integer> arr = new ArrayList<>();
        for (int i=0; i<nums.length; i++){
            if(nums[i]!=0){
                arr.add(nums[i]);
            }           
        }
        for(int j=0; j<arr.size(); j++){
            nums[j]=arr.get(j);
        }
        for (int k=arr.size(); k<nums.length; k++){
            nums[k]=0;
        }    
    }     
}

方法2:採用雙指標法.時間複雜度為O(n);  空間複雜度為O(1)

class Solution {
    public void moveZeroes(int[] nums) {
        int k=0;
        for (int i=0; i<nums.length; i++){
            if(nums[i]!=0){
                nums[k]=nums[i];
                k++;
            }
        }

        for (int j=k; j<nums.length; j++){
            nums[j]=0;
        }
    }
}

方法3: 優化方法2.時間複雜度O(n);  空間複雜度O(1) 

class Solution {
    public void moveZeroes(int[] nums) {
        int k=0;
        for(int i=0; i<nums.length; i++){
            if (nums[i]!=0){
                if(i!=k){   //優化點,去除同一個位置上的資料替換
                    int temp=nums[i];
                    nums[i]=nums[k];
                    nums[k]=temp;
                }                
                k++;               
            }
        }      
    }     
}

 

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。
注意這五個元素可為任意順序。
你不需要考慮陣列中超出新長度後面的元素

採用雙指標法.時間複雜度為O(n);  空間複雜度為O(1)

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

 

26. 刪除排序陣列中的重複項 

給定一個排序陣列,你需要在原地刪除重複出現的元素,使得每個元素只出現一次,返回移除後陣列的新長度。

不要使用額外的陣列空間,你必須在原地修改輸入陣列並在使用 O(1) 額外空間的條件下完成。

示例 1:

給定陣列 nums = [1,1,2], 

函式應該返回新的長度2, 並且原陣列 nums 的前兩個元素被修改為 。 

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

示例 2:

給定 nums = [0,0,1,1,1,2,2,3,3,4],
函式應該返回新的長度 5, 並且原陣列 nums 的前五個元素被修改為 0,1,2,3,4。
你不需要考慮陣列中超出新長度後面的元素。

class Solution {
    public int removeDuplicates(int[] nums) {
        int k=1;
        for (int i=1; i<nums.length; i++){
            if (nums[i]!=nums[i-1]){
                if(k!=i){
                    nums[k]=nums[i];
                }
                
                k++;
            }
        }
        return k;
    }
}

 

80.刪除排序陣列中的重複項 II 

給定一個排序陣列,你需要在原地刪除重複出現的元素,使得每個元素最多出現兩次,返回移除後陣列的新長度。

不要使用額外的陣列空間,你必須在原地修改輸入陣列並在使用 O(1) 額外空間的條件下完成。

示例 1:

給定 nums = [1,1,1,2,2,3],

函式應返回新長度 length =5, 並且原陣列的前五個元素被修改為1, 1, 2, 2,3 。

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

示例 2:

給定 nums=[0,0,1,1,1,1,2,3,3],函式應返回新長度 length =7,並且原陣列的前五個元素被修改為0,0,1,1,2,3,3 。
你不需要考慮陣列中超出新長度後面的元素。

class Solution {
    public int removeDuplicates(int[] nums) {
     // 如果資料少於2,肯定合法
        if (nums.length<=2){
            return nums.length;
        }
        
        int k=1;
        int count=1;  //記錄一個數字出現的次數
        for (int i=1; i<nums.length; i++){
            if (nums[i]==nums[i-1]){
                count++;
                if(count<3){
                    if(k!=1){
                        nums[k]=nums[i];
                    }
                    k++;
                }
            }else{
                count=1;
                nums[k]=nums[i];
                k++;               
            }
        }
        return k;
    }
}