程式碼隨想錄演算法訓練營,29日 | 704. 二分查詢,27. 移除元素,977.有序陣列的平方,209.長度最小的子陣列,59.螺旋矩陣II

漪欢酒發表於2024-08-29

陣列基礎
文件講解︰程式碼隨想錄(programmercarl.com)
1.連續空間、相同型別元素
2.元素只能覆蓋
3.二維陣列的地址連續嗎(C++連續,Java不連續)

704. 二分查詢
題目連結:704. 二分查詢
文件講解︰程式碼隨想錄(programmercarl.com)
影片講解︰二分查詢
日期:2024-08-29

思路:第一反應是想到二分查詢的前提:陣列升序,無重複元素;第二點是,確定區間是左閉右開還是左閉右閉,這樣才能確定是左右大小比較是<、還是<=。
Java程式碼如下:

//左閉右閉
class Solution {
    public int search(int[] nums, int target) {
        int left = 0, right = nums.length - 1;
        while(left <= right){
            int mid = left + (right - left)/2;
            if(nums[mid] == target){
                return mid;
            }else if(nums[mid] < target){
                left = mid + 1;
            }else{
                right = mid - 1;
            }
        }
        return -1;
    }
}
//左閉右開
class Solution {
    public int search(int[] nums, int target) {
        int left = 0, right = nums.length;
        while(left < right){
            int mid = left + (right - left)/2;
            if(nums[mid] == target){
                return mid;
            }else if(nums[mid] < target){
                left = mid + 1;
            }else{
                right = mid;
            }
        }
        return -1;
    }
}

程式碼隨想錄給出一個最佳化的版本:

class Solution {
    public int search(int[] nums, int target) {
        // 避免當 target 小於nums[0] nums[nums.length - 1]時多次迴圈運算
        if (target < nums[0] || target > nums[nums.length - 1]) {
            return -1;
        }
        int left = 0, right = nums.length - 1;
        while (left <= right) {
            int mid = left + ((right - left) >> 1);
            if (nums[mid] == target) {
                return mid;
            }
            else if (nums[mid] < target) {
                left = mid + 1;
            }
            else { // nums[mid] > target
                right = mid - 1;
            }
        }
        // 未找到目標值
        return -1;
    }
}

總結:還要再熟悉下更新mid,尋找區間是左閉右開區間,right更新為mid而不是mid - 1,即:下一個查詢區間不會去比較nums[middle]。

27. 移除元素
題目連結:27. 移除元素
文件講解︰程式碼隨想錄(programmercarl.com)
影片講解︰移除元素
日期:2024-08-29

思路:1.暴力解法,兩層for,一層遍歷陣列找要移除的目標值,另一層是找到移除的值後,將其後面的值移前一位;2.快慢指標:快指標快在它會先走,遍歷整個陣列,慢指標:如果快指標遇到目標值了,它就不動了,否則將快指標的值給它,這樣的好處就是,兩個指標都從開頭起步,能很方便的找到目標值並用後面的值覆蓋。
Java程式碼如下:

//暴力
class Solution {
    public int removeElement(int[] nums, int val) {
        int size = nums.length;
        for(int i = 0; i < size; i++){
            if(nums[i] == val){
                for(int j = i + 1; j < size; j++){
                    nums[j - 1] = nums[j];
                }
                i--;
                size--;
            }
        }
        return size;
    }
}
//快慢指標
class Solution {
    public int removeElement(int[] nums, int val) {
        int slow = 0;
        for(int fast = 0; fast < nums.length; fast++){
            if(nums[fast] != val){
                nums[slow++] = nums[fast];
            }
        }
        return slow;
    }
}

程式碼隨想錄還提供了用相向雙指標的演算法,我用的是同向的:

//相向雙指標法
class Solution {
    public int removeElement(int[] nums, int val) {
        int left = 0;
        int right = nums.length - 1;
        while(right >= 0 && nums[right] == val) right--; //將right移到從右數第一個值不為val的位置
        while(left <= right) {
            if(nums[left] == val) { //left位置的元素需要移除
                //將right位置的元素移到left(覆蓋),right位置移除
                nums[left] = nums[right];
                right--;
            }
            left++;
            while(right >= 0 && nums[right] == val) right--;
        }
        return left;
    }
}

總結:第一次用雙指標的地方,之前面試有被問過什麼時候用雙指標的地方,後面遇到多了再總結。總的來說就是一邊迴圈裡幹兩遍迴圈的事。

977.有序陣列的平方
題目連結:977.有序陣列的平方
文件講解︰程式碼隨想錄(programmercarl.com)
影片講解︰有序陣列的平方
日期:2024-08-29

思路:1.暴力思路,平方後再快排; 2.注意到陣列是有序的,那麼對於平方後的最大數只會在頭或者尾產生,所有兩個指標一個在頭一個在尾平方比大小,把較大的值放到一個新陣列的末尾就行了。
Java程式碼如下:

class Solution {
    public int[] sortedSquares(int[] nums) {
        int[] result = new int[nums.length];
        int left = 0;
        int right = nums.length - 1;
        int i = nums.length - 1;
        while(left <= right){
            if(nums[left] * nums[left] <= nums[right] * nums[right]){
                result[i--] = nums[right] * nums[right];
                right--;
            }else{
                result[i--] = nums[left] * nums[left];
                left++;
            }
        }
        return result;
    }
}

總結:注意一定要是有序的陣列才能這麼操作,面試被坑過(

209.長度最小的子陣列
題目連結:209.長度最小的子陣列
文件講解︰程式碼隨想錄(programmercarl.com)
影片講解︰長度最小的子陣列
日期:2024-08-29

思路:看題第一眼就是滑動視窗(總算記住了),陣列跟著前指標的移動逐加,直到和大於等於目標,記錄此時子陣列長度,此時移動一位後指標,前指標再接著走,接著加,再出現大於等於目標時比較之前的長度和這一次的,取最小值,最後返回時還要判斷到底存不存在這個子陣列
Java程式碼如下:

class Solution {
    public int minSubArrayLen(int target, int[] nums) {
        int result = Integer.MAX_VALUE;
        int i = 0, sum = 0;
        for(int j = 0; j < nums.length; j++){
            sum += nums[j];
            while(sum >= target){
                result = Math.min((j - i + 1), result);
                sum -= nums[i++];
            }
        }
        return result == Integer.MAX_VALUE? 0: result;
    }
}

總結:不熟悉Java語法,Integer.MAX_VALUE,Math.min,滑動視窗這名字還是很形象的,主要用在早最小區間。

59.螺旋矩陣II
題目連結:59.螺旋矩陣II
文件講解︰程式碼隨想錄(programmercarl.com)
影片講解︰螺旋矩陣II
日期:2024-08-29

思路:首先是找不變數,在本題中就是區間的劃分,上下左右都得是同樣的區間(左閉右開)才能清楚明白的寫下去,還有就是完成這套題需要一些什麼值要搞清楚,迴圈起始位置(怎麼調整它:需要一個調整值),迴圈次數,填的數(從1開始),最後就是這個二維矩陣的中心有沒有,確定了這些思路就清楚了
Java程式碼如下:

class Solution {
    public int[][] generateMatrix(int n) {
        int result[][] = new int[n][n];
        int startx = 0, starty = 0;
        int loop = n / 2;
        int mid = n / 2;
        int offset = 1;
        int count = 1;
        while(loop-- > 0){
            int i = startx;
            int j = starty;
            for(; j < n - offset; j++){
                result[i][j] = count++;
            }
            for(; i < n - offset; i++){
                result[i][j] = count++;
            }
            for(; j > 0; j--){
                result[i][j] = count++;
            }
            for(; i > 0; i--){
                result[i][j] = count++;
            }
            startx++;
            starty++;
            offset++;
        }
        if(n % 2 != 0) result[mid][mid] = n * n;
        return result;
    }
}

總結:錯在了對二維陣列兩個角標的理解上,還有這裡每個值的意義要搞明白。

相關文章