コードランダム記録アルゴリズム合宿2日目 | 907個の規則配列、209個の最小長部分配列、59個のスパイラル行列II

今日学んだ記事とビデオへのリンク

977記事リンク:リンク
977動画解説リンク:リンク
209記事リンク:リンク
209動画解説リンク:リンク
59記事リンク:リンク
59動画解説リンク:リンク

977 数値配列の二乗

最初にタイトルを見てください

タイトルは、各数値の 2 乗を返し、整数配列の新しい配列を非降順で返すことになっているため、非降順でソートすることも必要です。次のようなアイデアがあります。

  1. まず配列内の要素を二乗します
  2. 数値を素早く並べ替えるためのコードは
    次のとおりです。
class Solution {
    
    
public:
    vector<int> sortedSquares(vector<int>& nums) {
    
    
        for (int i = 0; i < nums.size(); i++) {
    
    
            nums[i] *= nums[i];
        }
        sort(nums.begin(), nums.end()); // 快速排序
        return nums;
    }

コードカプリスを読んだ感想

私が考えた暴力的なソートは、コードのランダムな思考で言及されており、その時間計算量は O(n + nlogn) ですが、より時間計算量の低い別の方法、ダブル ポインター法があります

ダブルポインタ方式

配列は順序付けされているため (負の数が含まれる場合があります)、配列の 2 乗後の最大値は配列の両端にある必要があるため、ダブル ポインター方式を考慮できます。i は開始位置を指し、j は点を指します。終了位置へ。

k が結果配列の終了位置を指すように、新しい配列結果を定義する必要があります。そのサイズは nums と同じです。

もしnums[i] * nums[i] > nums[j] * nums[j]それresult[k--] = nums[i] * nums[i]
ならnums[i] * nums[i] <= nums[j] * nums[j]_result[k--] = nums[j] * nums[j]

導入中に遭遇した困難

vector<int> result(nums.size(), 0);この文がよくわかりません
ベクトルを初期化する方法としてこれを問い合わせてください。


vector<int> result(nums.size(), 0); //初始化,第一个参数是数目,第二个参数是要初始化的值

コード

class Solution {
    
    
public:
    vector<int> sortedSquares(vector<int>& nums) {
    
    
        vector<int> result(nums.size(), 0);
        int k= nums.size()-1;
        for(int i = 0,j = nums.size()-1;i <= j;){
    
    
            if(nums[i] * nums[i] > nums[j] * nums[j]){
    
    
                result[k--] = nums[i] * nums[i];
                i++;
            }
            else{
    
    
                result[k--] = nums[j] * nums[j];
                j--;
            }
        }
        return result;
    }
};

209 最小の長さのサブ配列

最初にタイトルを見てください

タイトルの説明:正の整数を含む配列と正の整数
を指定します合計 [num sl s_l]を満たす配列内の最小の連続部分配列を見つけます。ntarget
≥ targetssl + 1 s_{l+1}かどうかsl + 1, …, num sr − 1 s_{r-1}sr 1、数値sr s_rsr] を返し、その長さを返します。条件を満たす部分配列がない場合は、それを返します0
タイトルの要件を満たすために必要な連続部分配列を見て、スライディング ウィンドウ法を思いつきました。

コードカプリスを読んだ感想

コードのランダム記録では、スライディング ウィンドウ方式も推奨されます。

スライディング ウィンドウの意味は、必要な結果を得るためにサブシーケンスの開始位置と終了位置を継続的に調整することです。

for ループは 1 つだけ使用され、このループのインデックスはスライディング ウィンドウの終了位置を示す必要があります。

では、アクティブウィンドウの開始位置を移動するにはどうすればよいでしょうか?

現在のウィンドウの値が s より大きい場合、ウィンドウは前方に移動します。

導入中に遭遇した困難

考え方は正しいのですが、実際にコードを操作する際にウィンドウの初期位置を移動させるのが少し難しいです。

コードのこの部分は次のとおりです。

while (sum >= s) {
    
    
	subLength = (j - i + 1); // 取子序列的长度
 	result = result < subLength ? result : subLength;
	sum -= nums[i++]; //这里体现了滑动窗口的精髓之处,不断变更i(子序列的起始位置)

コード

class Solution {
    
    
public:
    int minSubArrayLen(int target, vector<int>& nums) {
    
    
        int result = INT32_MAX;
        int sum = 0;//滑动窗口数值之和
        int i = 0;//滑动窗口起始位置
        int subLength = 0;//滑动窗口长度
        for (int j = 0;j < nums.size();j++){
    
    
            sum += nums[j];
            while (sum >= target){
    
    
                subLength = (j - i + 1);
                result = result < subLength ? result : subLength;
                sum -= nums[i++];
            }
        }
        return result == INT32_MAX ? 0 : result;
    }
};

59 スパイラルマトリックスⅡ

最初にタイトルを見てください

タイトルの説明:
正の整数を指定して、1 ~ n 2 n^2nを含む整数を生成しますn2すべての要素、および要素はn x n正方matrix
この問題を見て、この問題を解く鍵は境界条件の扱いであり、ループ不変性の原則に従わなければならないと思いました。

コードカプリスを読んだ感想

コードのランダムな思考で強調されるのは、ループ不変の原則に従うことです

時計回りに行列を描画するプロセスをシミュレートします。

  • 上の行を左から右に埋めていきます
  • 右の列を上から下まで埋めてください
  • 降順の行を右から左に埋めていきます
  • 左の列を下から上に埋めていきます

外側から内側に向​​かって円を描きます。

このようなループでは、処理の鍵となるのが境界条件であり、一定のルールに従って巡回しないとループに迷い込みやすくなります。

したがって、各面を描くときは、左閉じと右開き、または左開きと右閉じの原則を遵守し、統一されたルールに従って描くことができ、迷子にならないようにする必要があります

導入中に遭遇した困難

コード中のwhileループでは判定する条件が多数あるので、条件の変化を考えるために動的グラフを描くことを推奨します。
ここに画像の説明を挿入

Carl's Code Random Thoughts Web サイトからの画像

コード

class Solution {
    
    
public:
    vector<vector<int>> generateMatrix(int n) {
    
    
        vector<vector<int>> res(n, vector<int>(n, 0)); // 使用vector定义一个二维数组
        int startx = 0, starty = 0; // 定义每循环一个圈的起始位置
        int loop = n / 2; // 每个圈循环几次,例如n为奇数3,那么loop = 1 只是循环一圈,矩阵中间的值需要单独处理
        int mid = n / 2; // 矩阵中间的位置,例如:n为3, 中间的位置就是(1,1),n为5,中间位置为(2, 2)
        int count = 1; // 用来给矩阵中每一个空格赋值
        int offset = 1; // 需要控制每一条边遍历的长度,每次循环右边界收缩一位
        int i,j;
        while (loop --) {
    
    
            i = startx;
            j = starty;

            // 下面开始的四个for就是模拟转了一圈
            // 模拟填充上行从左到右(左闭右开)
            for (j = starty; j < n - offset; j++) {
    
    
                res[startx][j] = count++;
            }
            // 模拟填充右列从上到下(左闭右开)
            for (i = startx; i < n - offset; i++) {
    
    
                res[i][j] = count++;
            }
            // 模拟填充下行从右到左(左闭右开)
            for (; j > starty; j--) {
    
    
                res[i][j] = count++;
            }
            // 模拟填充左列从下到上(左闭右开)
            for (; i > startx; i--) {
    
    
                res[i][j] = count++;
            }

            // 第二圈开始的时候,起始位置要各自加1, 例如:第一圈起始位置是(0, 0),第二圈起始位置是(1, 1)
            startx++;
            starty++;

            // offset 控制每一圈里每一条边遍历的长度
            offset += 1;
        }

        // 如果n为奇数的话,需要单独给矩阵最中间的位置赋值
        if (n % 2) {
    
    
            res[mid][mid] = count;
        }
        return res;
    }
};

今日は収穫

1. ダブルポインタ方式のソート方法をマスターすれば、激しいソートとはバイバイできる

2. スライディングウィンドウを実装する場合は、次の 3 つの点を考慮してください。

  • 窓の中には何があるの?
  • ウィンドウの開始位置を移動するにはどうすればよいですか?
  • ウィンドウの終了位置を移動するにはどうすればよいですか?

3. スパイラル行列の問題に遭遇した場合、ループ内で迷子になることを避けるために、ループ不変性の原則に従う必要があります。

今日の勉強時間は3時間です

おすすめ

転載: blog.csdn.net/m0_46555669/article/details/126999364