[Super detailed ~] the use of double pointer algorithm

1. Usage scenario:

Generally, when it is necessary to fetch a certain segment of the array elements, the fast and slow pointers can be parallelized

The double pointer method (fast and slow pointer method) is very common in the operation of arrays and linked lists. Many interview questions that investigate operations on arrays, linked lists, and strings use the double pointer method.

2. Type:

Fast and slow pointers, head and tail pointers, sliding windows, etc.

3. How to use

(1) The j in the for loop is equivalent to a pointer

Then you can define a global variable i as another pointer, and use i++ to move the pointer in for

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

(2) Sometimes two pointers are directly defined in the for loop

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

4. Application scenarios

(1) Remove elements from the array

Given an array nums and a value val, you need to remove all elements whose value is equal to val in place, and return the new length of the removed array.

Don't use extra array space, you have to use only O(1) extra space and modify the input array in-place .

The order of elements can be changed. You don't need to consider elements in the array beyond the new length.

Idea: fast pointer to find the elements of the new array (elements not equal to val)

The slow pointer identifies where the new array is currently capable of adding new elements (actually overwriting elements of the old array)

// 时间复杂度: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) The square of an ordered array (arrays in non-decreasing order, positive and negative)

Given an array of integers nums sorted in non-decreasing order, return a new array consisting of the square of each number, also sorted in non-decreasing order.

Idea: a head pointer, a tail pointer

Compare the square values ​​of the elements currently pointed to by the two, and put them into the result set

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) The subarray with the smallest length

Given an array containing n positive integers and a positive integer s, find the smallest continuous subarray whose sum ≥ s in the array, and return its length. Returns 0 if no matching subarray exists.

Idea: The sliding window can also be understood as a kind of double pointer method!

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

Guess you like

Origin blog.csdn.net/m0_58768224/article/details/129797030