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;
}
};