演算法訓練day2

TomatoErn發表於2024-11-28

209.長度最小的子陣列https://leetcode.cn/problems/minimum-size-subarray-sum/: 給定一個含有n個正整數的陣列和一個正整數target。找出該陣列中滿足其總和大於等於target的長度最小的子陣列[nums_l, nums_{l+1}, ..., nums_{r-1}, nums_r],並返回其長度。如果不存在符合條件的子陣列,返回0
(1)暴力求解法:利用兩個迴圈,分別遍歷子列的起始位置和終止位置;若檢查到和>= target的子列,將其長度記為len;實時更新滿足條件的最短子列長s。

class Solution {
public:
    int minSubArrayLen(int target, vector<int>& nums) {
        int sum = 0, len = 0, s = nums.size()+10;
        for (int i = 0; i < nums.size(); i++){
            sum = 0;
            for (int j = i; j <nums.size(); j++){
                sum += nums[j];
                if (sum >= target) {
                   len = j-i+1;
                   break; 
                }
                else len = nums.size()+10;
            }
            if (s > len) s = len;
       }
       return s == nums.size() + 10 ? 0 : s;
    }
};

時間複雜度:O(n^2),這導致當n很大時超出時間限制;
空間複雜度:O(1)
(2)移動視窗解法:利用一個for迴圈遍歷視窗終止位置,以其和sum是否大於target作為元素是否在視窗中的依據。若sum小於target,向後移動視窗終止位置;若sum大於target,向後移動視窗起始位置。注意移動時和sum的變化;並實時記錄和比較子列長度。

class Solution {
public:
    int minSubArrayLen(int target, vector<int>& nums) {
        int sum = 0, sublenth = 0, result = INT32_MAX;
        int i = 0; //star index
        for (int j = 0; j < nums.size(); j++){
            sum += nums[j];
            while(sum >= target){
                sublenth = j - i + 1;
                result = result < sublenth ? result : sublenth;
                sum -= nums[i++]; // 這裡體現出滑動視窗的精髓之處,不斷變更i
                continue;
            }
       }
       return result == INT32_MAX ? 0 : result;
    }
};

空間複雜度:O(n)
時間複雜度:O(1)
(3)解題困難:①不能準確判斷移動視窗的起始位置i和終止位置j的設定;②嘗試先固定子陣列長度,再找滿足和條件的子陣列,最終還是要用兩個迴圈。

59.螺旋矩陣https://leetcode.cn/problems/spiral-matrix-ii/: 給你一個正整數n,生成一個包含1n^2所有元素,且元素按順時針順序螺旋排列的n x n正方形矩陣matrix
(1)自我思路:n為奇數時有中心,為偶數時只有外圈;一圈四邊,每邊的元素數目只計算左閉右開區間內的元素。
(2)迴圈求解:

class Solution {
public:
    vector<vector<int>> generateMatrix(int n) {
        std::vector<std::vector<int>> arr(n, std::vector<int>(n,0));
        int loop = n / 2; //記錄要填充圈數,n為奇數時還需要單獨處理中間位置
        int startx = 0, starty = 0; // 定義每迴圈一個圈的起始位置
        int mid = n/2;//記錄中間位置
        int offset = 1;
        int count = 1;
        int i, j;
        while (loop--){
            i = startx; j = starty;
            for (j; j < n - offset; j++){ //j從0變到n-offset,n-offset未進入迴圈
                arr[i][j] = count++;
            }
            for (i; i < n - offset; i++) {//j從0變到n-1
                arr[i][j] = count++;
            }
            for (; j > startx; j--){ //j從n-offset 變到startx
                rr[i][j] = count++;
            }
            for (; i > starty; i--){ //i從n-offset 變到starty
                arr[i][j] = count++;
            }
            // 第二圈開始的時候,起始位置要各自加1
            startx++;
            starty++;
            // offset 控制每一圈裡每一條邊遍歷的長度
            offset += 1;
        }
        if (n % 2) arr[mid][mid] = n*n;
        return arr;
    }
};

時間複雜度:O(n^2)
空間複雜度:O(1)
(3)主要困難:誤用行列乘積給元素賦值;區間端點i與j的設定;
(4)收穫:自增運算子有共同效果和細微區別。① 字尾自增:i++ 會先返回 i 的當前值,然後 i 的值增加1。② 字首自增:++i 會先將 i 的值增加1,然後返回 i 的新值。例如

int i = 1;
int a = i++; // a = 1, i = 2
int b = ++i; // i = 3, b = 3

相關文章