【超詳しい〜】ダブルポインタアルゴリズムの利用

1. 使用シナリオ:

一般に、配列要素の特定のセグメントをフェッチする必要がある場合、高速ポインタと低速ポインタを並列化できます。

ダブル ポインタ メソッド (高速ポインタ メソッドとスロー ポインタ メソッド) は、配列やリンク リストの操作で非常に一般的であり、配列、リンク リスト、文字列の操作を調査する面接の質問の多くでダブル ポインタ メソッドが使用されます。

2. 次のように入力します。

高速ポインタと低速ポインタ、ヘッドポインタとテールポインタ、スラ​​イディングウィンドウなど。

3. 使用方法

(1) for ループ内の j はポインタに相当します。

次に、グローバル変数 i を別のポインターとして定義し、i++ を使用してそのポインターを次のように移動します。

let i = 0
for (let j = 0; j < arr.length; j++){
    
    
    arr[i++] = arr[j]
}

(2) for ループ内で 2 つのポインタが直接定義される場合があります。

for (let i = 1, j = 0; arr[i] < arr[j]){
    
    
    
}

4. 応用シナリオ

(1) 配列から要素を削除する

配列 nums と値 val が与えられた場合、値が val に等しいすべての要素をその場で削除し、削除された配列の新しい長さを返す必要があります。

余分な配列スペースを使用しないでください。O(1) の追加スペースのみを使用し、入力配列をインプレースで変更する必要があります。

要素の順序は変更できます。新しい長さを超える配列内の要素を考慮する必要はありません。

アイデア: 新しい配列の要素 (val に等しくない要素) を見つけるための高速ポインター

スロー ポインタは、新しい配列が現在新しい要素を追加できる場所 (実際には古い配列の要素を上書きする) を識別します。

// 时间复杂度:O(n)
// 空间复杂度:O(1)
class Solution {
public:
    int removeElement(vector<int>& nums, int val) {
        int slowIndex = 0;
        for (int fastIndex = 0; fastIndex < nums.size(); fastIndex++) { //一开始两个指针都指向一个元素
            if (val != nums[fastIndex]) { //一旦等于,快指针就把慢指针甩开了
                nums[slowIndex++] = nums[fastIndex]; //一开始相当于自己给自己赋值
                //一旦甩开了就是后一个给前一个赋值
            }
        }
        return slowIndex;
    }
};

(2) 順序付けされた配列 (正と負の非降順の配列) の 2 乗

非降順でソートされた整数 nums の配列を指定すると、同じく非降順でソートされた各数値の 2 乗で構成される新しい配列を返します。

アイデア: ヘッド ポインター、テール ポインター

現在 2 つが指している要素の 2 乗の値を比較し、結果セットに入れます。

class Solution {
public:
    vector<int> sortedSquares(vector<int>& A) {
        int k = A.size() - 1; //指向新数组,从尾部开始移动
        vector<int> result(A.size(), 0); //新数组
        for (int i = 0, j = A.size() - 1; i <= j;) { // 注意这里要i <= j,因为最后要处理两个元素
            if (A[i] * A[i] < A[j] * A[j])  {
                result[k--] = A[j] * A[j];
                j--;
            }
            else {
                result[k--] = A[i] * A[i];
                i++;
            }
        }
        return result;
    }
};

(3) 最小の長さの部分配列

n 個の正の整数と 1 つの正の整数 s を含む配列を指定すると、配列内で合計が s より大きくなる最小の連続部分配列を見つけ、その長さを返します。一致するサブ配列が存在しない場合は 0 を返します。

アイデア: スライディング ウィンドウは、ダブル ポインター メソッドの一種として理解することもできます。

class Solution {
public:
    int minSubArrayLen(int s, 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,每次更新 i(起始位置),并不断比较子序列是否符合条件
            while (sum >= s) { //一旦和超过了目标值
                subLength = (j - i + 1); // 取子序列的长度
                result = result < subLength ? result : subLength; //如果出现了更短的,就把结果改成更短的
                sum -= nums[i++]; // 移除第一个元素。这里体现出滑动窗口的精髓之处,不断变更i(子序列的起始位置)
            }
        }
        // 如果result没有被赋值的话,就返回0,说明没有符合条件的子序列
        return result == INT32_MAX ? 0 : result;
    }
};

おすすめ

転載: blog.csdn.net/m0_58768224/article/details/129797030