Double pointer algorithm

Posted by pacome on Sat, 04 Dec 2021 22:44:41 +0100

preface

After listening to one of the basic algorithm classes held by yxc in acwing and listening to the double pointer algorithm, I feel that in fact it is still a violent method, but after analysis, it is actually an O(n) algorithm. I can't help but be a little curious. At the beginning, I didn't understand it. I always feel that it still has two layers of loops, but after analysis, I found that all its elements have been traversed at most, The two pointers go 2n times at most. It felt a little strange, so I wrote a note.

Double pointer algorithm

In fact, we have been in contact with the double pointer algorithm, but we don't know it ourselves. Where have we been in contact? Yes, when writing merge sort code and quick sort code. Here, I cite a piece of code for merging and sorting as an example.

/* Merge operation */
void merge(int arr[],int l,int mid ,int r){
    int p1=l,p2=mid+1;
    int help[r-l+1],i=0;
    while(p1<=mid && p2<=r){
        help[i++]=arr[p1]<=arr[p2]?arr[p1++]:arr[p2++];
    }
    /* Import unfinished data to help */
    while(p1<=mid){
        help[i++]=arr[p1++];
    }
    while(p2<=r){
        help[i++]=arr[p2++];
    }
    /* Copy the help array back to arr. Note that the range from l to r is merged, not the 0-end */
    for(int k=0;k<i;k++){
        arr[l+k]=help[k];
    }
}

What is our approach to merge and sort? Whether to divide the array into two segments, sort the two segments respectively, and then integrate the two segments into an array. This integration process uses the double pointer algorithm. Let's look at the above code. Our two pointers P1 and p2 point to the ordered two segments respectively, and then we judge the size of the values of arr[p1] and arr[p2]. If arr[p1] is small, put arr[p1] Fill in the middle array, and then P1 moves back. The same is true for p2. In other words, we can use two pointers to orderly arrange the two ordered arrays into the third array. The principle is that whoever is young will be loaded in until it is finished. In this way, we will find that P1 only accesses each value on the left half of the array, the same For the array on the right, p2 only accesses it once, that is, two ordered arrays (set as array 1 and array 2) are integrated into one array (also ordered) , assuming that the length of array 1 is a and the length of array 2 is B, then the most correct pair of operands required for the integration operation is a+b. if we fix a value of an array and then traverse all the values of another array, the complexity is O(a*b). It can be seen that the optimization effect can be achieved by using the double pointer algorithm.

Double pointer algorithm

Originally, I thought there was only one way to write the double pointer algorithm, that is, the one taught by teacher y, but I looked at the problem of merging and sorting. It seemed that it was also a way to write, and it seemed easier to understand. Here, give both templates

This is the template given by y teacher:

for (int i = 0, j = 0; i < n; i ++ )
{
    while (j < b && check(i, j)) j ++ ;

    // Logic of specific problems (what are the requirements of the topic)
}
Classification of frequently asked questions:
    (1) For a sequence, maintain an interval with two pointers
    (2) For two sequences, maintain a certain order, such as merging two ordered sequences in merge sort

Let's explain the general meaning of the above code, that is, both i and j start from 0, and then if the thing J refers to satisfies some properties or he does not reach the boundary, j + +, use the above merging sort to explain: if arr[p2] < arr [p1], then i put arr[p2] Save help, and then p2 + +. If the next one is still satisfied, perform the same operation until arr[p2] > = arr [p1]. At this time, the person performing the above operation becomes p1, and then know that all the arrays are judged. Here, i rewrite the code for merging and sorting above to facilitate understanding:

/* Merge operation */
void merge(int arr[], int l, int mid, int r) {
    int help[r - l + 1], i = 0;
    for (int p1 = l, p2 = mid + 1; p1 <= mid; p1++) {
        while (arr[p2] < arr[p1] && p2 <= r) help[i++] = arr[p2++];
        help[i++] = arr[p1];
    }
    /* Copy the help array back to arr. Note that the range from l to r is merged, not the 0-end */
    for (int k = 0; k < i; k++) {
        arr[l + k] = help[k];
    }
}

This is another form:

while(i<=a&&j<=b){
    ······
}
while(i<=a){//Handle i unfinished business
    ······
}
while(j<=b){
    ······
}

Personally, I think this one is easier to understand

Take CCF-CSP, 202006-2 sparse vector as an example

In this blog, I use the above two solutions as examples. You can go there and have a look.

end

Well, it's finished here.

Topics: Double Pointer