1. 程式人生 > >領釦-26/27/80/283 陣列專題 做好初始定義 雙指標 MD

領釦-26/27/80/283 陣列專題 做好初始定義 雙指標 MD

目錄

Markdown版本筆記 我的GitHub首頁 我的部落格 我的微信 我的郵箱
MyAndroidBlogs
baiqiantao baiqiantao bqt20094 [email protected]

領釦-26/27/80/283 陣列專題 做好初始定義 雙指標 MD
***
目錄
===

陣列專題:做好初始定義

做陣列類演算法問題的時候,我們常常需要定義一個變數,明確該變數的定義,並且在書寫整個邏輯的時候,要不停的維護住這個變數的意義。也特別需要注意初始值和邊界的問題。

移動零 Move Zeroes -283

陣列 雙指標

問題

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

示例:

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

說明:

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

答案

class Solution {
    public void moveZeroes(int[] nums) {
        int count = 0;//零的個數
        for (int i = 0; i < nums.length; i++) {
            if (nums[i] == 0) {
                count++;
            } else {
                nums[i - count] = nums[i]; //非零往前移
            }
        }
        int n = nums.length;
        while (count > 0) {
            nums[n - count] = 0; //填充後面的零
            count--;
        }
    }
}

移除元素 Remove Element -27

陣列 雙指標

問題

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

  • 不要使用額外的陣列空間,你必須在原地修改輸入陣列。
  • 元素的順序可以改變。
  • 你不需要考慮陣列中超出新長度後面的元素。

示例 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。
注意這五個元素可為任意順序。

答案

這題廢話連篇,其實和上一題核心步驟完全相同,而比上一題還容易。

class Solution {
    public int removeElement(int[] nums, int val) {
        int count = 0;//個數
        for (int i = 0; i < nums.length; i++) {
            if (nums[i] == val) {
                count++;
            } else {
                nums[i - count] = nums[i]; //往前移
            }
        }
        return nums.length - count;
    }
}

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

陣列 雙指標

問題

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

  • 不要使用額外的陣列空間,你必須在原地修改輸入陣列。
  • 你不需要考慮陣列中超出新長度後面的元素。

示例 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。

記錄位置法

沃日,這個問題我修改了很多了版本,都有問題,全是邊界問題搞得怪!

問題分析起來很簡單,就是記錄重複元素的個數 count,然後把後面不重複的元素根據 count 移到前面來。

class Solution {
    public int removeDuplicates(int[] nums) {
        int count = 0;//刪除個數個數,1, 2, 2, 3, 3, 4 
        for (int i = 0; i < nums.length - count; i++) {
            for (int j = i + count + 1; j < nums.length && nums[j] == nums[i + count]; j++) {
                count++;
            }
            nums[i] = nums[i + count]; //往前移
        }
        return nums.length - count;
    }
}

快慢指標法

解題思路是,我們使用快慢指標來記錄遍歷的座標,最開始時兩個指標都指向第一個數字

  • 如果兩個指標指的數字相同,則快指標向前走一步
  • 如果不同,則兩個指標都向前走一步
    這樣當快指標走完整個陣列後,慢指標當前的座標加1就是陣列中不同數字的個數。
class Solution {
    public int removeDuplicates(int[] nums) {
        if (nums.length == 0) return 0;

        int fast = 1, slow = 0;
        while (fast < nums.length) {
            if (nums[fast] != nums[slow]) {
                slow++;
                nums[slow] = nums[fast];
                //這兩行程式碼可以簡化為 nums[++slow] = nums[fast];
            }
            fast++;
        }
        return slow + 1;
    }
}

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

陣列 雙指標

問題

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

  • 不要使用額外的陣列空間,你必須在原地修改輸入陣列。
  • 你不需要考慮陣列中超出新長度後面的元素。

答案

這道題和上面相比沒有多大的區別,關鍵是邏輯問題,如果腦筋轉不過來彎,那很難正確處理指標位置的。

class Solution {
    public int removeDuplicates(int[] nums) {
        if (nums.length <= 2) return nums.length;
        int fast = 1, slow = 0;
        boolean isRepeat = false;

        while (fast < nums.length) {
            if (nums[fast] == nums[slow] && isRepeat) fast++; //【3】之後再發現重複的數後,直接跳過,直到發現另一個數
            else {
                isRepeat = nums[fast] == nums[slow];//【1】判斷是不是重複的數
                nums[++slow] = nums[fast++]; //【2】第一次發現重複的數後,並沒有跳過這個數,而是按照正常邏輯接收了這個數
            }
        }
        return slow + 1;
    }
}

2018-12-16