Kiner algorithm brush inscription: fast platoon and fast platoon idea (hand tearing algorithm)

Posted by wvwisokee on Tue, 01 Feb 2022 08:41:52 +0100

Guide to series of articles

preface

After we are familiar with the idea and implementation principle of quick sort, we can bring a lot of inspiration and inspiration in our actual development. With the idea of double pointer walking of quick sort, we can also solve many kinds of quick sort problems. Now let's use some algorithm problems to consolidate the quick arrangement idea of the discussion.

Brush questions

Sword finger Offer 21 Adjust the array order so that odd numbers precede even numbers

Problem solving ideas

The point of this problem is that we need to find the odd and even numbers in the array and put them where they are changed according to the rules. With the help of the double pointer idea in the fast row, we can keep the left and right cursors swimming in the array. When the left cursor encounters an even number and the right cursor encounters an odd number, we can exchange the corresponding values of the left and right cursors, so as to realize the sorting of the left odd number and the right even number.

code implementation

function exchange(nums: number[]): number[] {
    // Judge boundary
    if(nums.length===0) return nums;

    // Define double pointer
    let x = 0, y = nums.length-1;
    // When we use the initial boundary, y must be greater than x, so when we use the initial boundary The while loop can reduce the judgment of some conditions
    do {
        // If the left cursor does not reach the boundary and the element pointed to by the left cursor is odd, move the left cursor to the right until it meets the even position
        // Num [x] & 1 uses binary and operation to judge odd and even numbers, which is more efficient and equivalent to num[x]%2
        while(x < nums.length && (nums[x] & 1)) x++;
        // Similarly, when the right cursor does not reach the left boundary and the value pointed by the right cursor is an even number, move the right cursor to the left until an odd number is encountered
        while(y >= 0 && (nums[y] & 1) === 0) y--;
        // After the above two moves, our left and right cursors have stayed at the even position and the odd position respectively. If the two cursors are not staggered, that is
        // If the left cursor still does not exceed the right cursor, we will exchange the array values corresponding to the left and right cursors, so that odd numbers can be placed on the left and even numbers can be placed on the right
        // After the exchange, you only need to make the left cursor take a step to the right, the right cursor wants to take a step to the left, and then enter the next cycle to continue processing
        if(x <= y) {
            [nums[x], nums[y]] = [nums[y], nums[x]];
            x++;
            y--;
        }
    } while (x <= y);

    return nums;
};

75. Color classification

Problem solving ideas

This problem can still use our fast scheduling idea to find the middle value as the reference value, and then set the left and right pointers as sentinels to wait. When the element value we traverse is less than the reference value, let the left sentinel exchange with it. When the traversed value is greater than the reference value, let the right sentinel exchange with it. After the exchange, don't forget to let the left and right sentinels close to the middle. If you encounter something equal to the benchmark value, do nothing and continue to traverse the next element

Code demonstration

/*
 * @lc app=leetcode.cn id=75 lang=typescript
 *
 * [75] Color classification
 */

// @lc code=start
/**
 Do not return anything, modify nums in-place instead.
 */

function sort(arr, l = 0, r = arr.length-1, mid = 1) {
    // If the left and right pointers coincide or cross the boundary, exit directly
    if(l >= r) return;
    // Define two sentinel cursors, with x in the front of the leftmost element and y in the back of the rightmost element
    // In this way, we can reduce a lot of conditional judgment, whether it is the first element or not, direct x + +,
    // Whether it is the last element or not, directly y--, is a bit similar to the sentinel node that we deal with the linked list problem
    let x = -1, y = r + 1, i = l;
    while(i < y) {
        if(arr[i] < mid) { // 0
            // If the current element is 0, move the left sentinel node one bit to the right
            x++;
            // Then exchange the values pointed to by the current node and the sentinel node
            [arr[i], arr[x]] = [arr[x], arr[i]];
            // After processing, the current node moves to the right
            i++;
        } else if(arr[i] === mid) {
            // If the current node is 1, we will ignore it, because we only need to put 0 to the left of 1
            // Just put 2 on the right side of 1. 1 will stay in place and move to the next node directly to the right
            i++;
        } else if(arr[i] > mid) {
            // If the current element is 2, let the sentinel on the right take a step to the left
            y--;
            // Then exchange the positions of the current node and the sentinel node
            [arr[i], arr[y]] = [arr[y], arr[i]];
        }
    }
}

function sortColors(nums: number[]): void {
    sort(nums);
};
// @lc code=end


Interview question 17.14 Minimum number of K

Problem solving ideas

We used heap sorting to solve this problem before. Now we use the idea of fast sorting to solve this problem. We only need to perform k-round fast sorting on the array (Note: we don't need to complete the fast sorting of the array, we only need to arrange k-round fast according to the meaning of the question, so the first k number of the array is the answer we want)

Code demonstration

// Take the middle of three points
function getMid(a: number, b: number, c: number): number {
    if(a > b) [a, b] = [b, a];
    if(a > c) [a, c] = [c, a];
    if(b > c) [b, c] = [c, b];
    return b;
}
// Fast selection method using fast scheduling idea
function quickSelect(arr, k, left = 0, right = arr.length-1) {
    // Exit when left cursor and right cursor meet or miss
    if(left >= right) return;
    // Get intermediate value
    let x = left, y = right, mid = getMid(arr[left], arr[Math.floor((left+right)/2)], arr[right]);
    do {
        // If the value on the left is less than the reference value, continue to move to the right
        while (arr[x] < mid) x++;
        // If the value on the right is greater than the reference value, continue on the left
        while (arr[y] > mid) y--;
        // When the left and right pointers meet, the corresponding values of the left and right pointers are exchanged
        if(x <= y) {
            [arr[x], arr[y]] = [arr[y], arr[x]];
            x++,y--;
        }
    } while (x <= y);
    // We only need to sort k bits, and there is no need to sort the rest
    if(y - left === k - 1) return;
    if(y - left >= k) { // If the number of intervals is greater than k, expand the range
        quickSelect(arr, k, left, y);
    } else {// If the number of intervals is greater than k, narrow the range
        quickSelect(arr, k - x + left, x, right);
    }
}

function smallestK(arr: number[], k: number): number[] {
    // Conduct k-wheel fast platoon
    quickSelect(arr, k);
    // Take the first k bits as the answer output
    return arr.slice(0, k);
};

11. Container with the most water

Problem solving ideas

This problem is also done by using the idea of double pointer. First of all, if we want to maximize the water receiving area, we must ensure that the width and height are as large as possible. We use double pointers to determine the width through the movement of the left and right cursors (width is the length in the middle of the left and right cursors, that is, the index of the right cursor minus the index of the left cursor). Because the left and right cursors are always close to the middle, Therefore, the width must be decreasing all the time, so our area depends on the height. Our height is the corresponding value of the left and right cursors. Because the actual height depends on which one is shorter, we need to take the minimum value and width of the left and right cursors to calculate the area, and take the maximum value compared with the previous calculation. In this way, after cycling, You get the maximum area.

code implementation

function maxArea(height: number[]): number {
  	// res is the maximum area, initially 0, l is the left cursor and r is the right cursor
    let res = 0, l = 0, r = height.length - 1;
  	// The left and right cursors did not meet
    while(l < r) {
      	// Calculate the area and compare it with the previous area to take the maximum value
        res = Math.max(res, (r - l) * Math.min(height[l], height[r]));
      	// In order to ensure that the height is as large as possible, if the height on the left is relatively small, move the left cursor to the right and change a left height
        if(height[l] < height[r]) l++;
      	// Otherwise, the right cursor moves left
        else r--;
    }
    return res;
};

Topics: Front-end Algorithm data structure quick sort