JS: Double pointer to solve the problem of array, catch the rain

26. Remove duplicates in sorted array (easy)

Given an ordered array nums, please delete the repeated elements in place so that each element appears only once, and return the new length of the deleted array.
Instead of using extra array space, you have to modify the input array in-place and do it with O(1) extra space.

/**
 * @param {number[]} nums
 * @return {number}
 */
var removeDuplicates = function(nums) {
    
    
    let i=0, len=nums.length;
    for (j=i+1; j<len; j++){
    
    
        if (nums[i]==nums[j]) continue;
        nums[++i] = nums[j]
    }
    return i+1 
};

27. Remove elements (simple)

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.
Instead of using 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.

Just modify the initial index of the previous question,

/**
 * @param {number[]} nums
 * @param {number} val
 * @return {number}
 */
var removeElement = function(nums, val) {
    
    
    let i=-1,len=nums.length;
    for (let j=0; j<len; j++){
    
    
        if (nums[j]==val) continue;
        nums[++i] = nums[j]
    }
    return i+1
};

283. Move Zero (Simple)

Given an array nums, write a function to move all 0s to the end of the array while maintaining the relative order of the non-zero elements.
Note that the array must be manipulated in-place without copying the array.

In fact, it is equivalent to removing all 0s in nums, and then assigning the following elements to 0.

/**
 * @param {number[]} nums
 * @return {void} Do not return anything, modify nums in-place instead.
 */
var moveZeroes = function(nums) {
    
    
    let i=-1,len=nums.length;
    for (let j=0; j<len; j++){
    
    
        if (nums[j]==0) continue;
        nums[++i] = nums[j]
    }
    i++;
    while (i<len) nums[i++] = 0;
};

42. Catch the rain (difficulty)

Given n non-negative integers representing the height map of each column with a width of 1, calculate how much rain the column can receive after it rains.
insert image description here

   My starting point was wrong, I aimed at the pillars (black), how many grids can be clamped by two pillars, but the problem is that the middle pillar will affect the original capacity. The double pointer induces me to start laterally.

Algorithm Cheat Sheet
Treat a string problem like a dynamic programming problem, don't think about what to do with the whole string, but think about how each character should be handled. For position i, how much water can it hold?
insert image description here
insert image description here

Brute-force solution: (timeout)

var trap = function(height) {
    
    
    let len = height.length, count=0;
    for (let i=1; i<len-1; i++){
    
    
        let le = 0, ri = 0;
        // 找右边最高的柱子
        for(let j = i; j < len; j++)
            ri = Math.max(ri, height[j])
        // 找左边最高的柱子
        for(let j = i; j > -1; j--)
            le = Math.max(le, height[j])
        count += Math.min(le, ri) - height[i]
    }
    return count;
};

Memorandum optimization
Record the height of the highest column on the left and right sides in advance, which further proves that the decisive factor of how much water can be held in position i.
insert image description here

var trap = function(height) {
    
    
    let len = height.length, count=0;
    let le = new Array(len), ri = new Array(len);
    le[0] = height[0], ri[len-1] = height[len-1];
    // i左边最高的柱子高度
    for (let i=1; i<len; i++){
    
    
        le[i] = Math.max(le[i-1], height[i])
    }
    // i右边最高的柱子高度
    for (let i=len-2; i>-1; i--){
    
    
        ri[i] = Math.max(ri[i+1], height[i])
    }
    for (let i=1; i<len-1; i++){
    
     
        count += Math.min(le[i], ri[i]) - height[i]
    }
    return count;
};

insert image description here

Double pointer solution:
The double pointer is based on the previous basis, reducing the number of l_max and r_max calculated. The decisive factor in understanding how much water can hold in position i has little to do with the double pointer.

insert image description here
insert image description here

If l_max < r_max, only pay attention to the left pointer, because you know the highest column to the left of the left pointer
If l_max > r_max, only pay attention to the right pointer, because you know the highest column to the right of the right pointer

This way you only need to look for the tallest pillar on one side.

var trap = function(height) {
    
    
    let len = height.length, count=0;
    let left = 0, right = len-1;
    let le_max = ri_max = -1;
    
    while(left<=right) {
    
    
        le_max = Math.max(height[left], le_max)
        ri_max = Math.max(height[right], ri_max)

        if (le_max <= ri_max){
    
    
            count += le_max - height[left];
            left++;
        } else{
    
    
            count += ri_max - height[right];
            right--;
        }
    }
    return count;
};

insert image description here

11. Container with the most water (medium)

You are given n non-negative integers a1, a2, ..., an, each representing a point (i, ai) in coordinates. Draw n vertical lines in the coordinates. The two endpoints of the vertical line i are (i, ai) and (i, 0) respectively. Find two of these lines that together with the x-axis form a container that holds the most water.

Note: You cannot tilt the container.

This problem eliminates the need to calculate how much water each position i can hold. The water contained is directly related to the left and right tallest pillars, and it is more connected to the double pointer: both sides are required to be tall and wide.
insert image description here

var maxArea = function(height) {
    
    
    let left=0, right=height.length-1, ans=0;
    let lmax = rmax = -1;
    while(left<=right){
    
    
        lmax = Math.max(lmax, height[left])
        rmax = Math.max(rmax, height[right])

        if(lmax <= rmax){
    
    
            ans = Math.max(ans, lmax * (right-left))
            left++
        }else{
    
    
            ans = Math.max(ans, rmax * (right-left))
            right--
        }
    }
    return ans;
};

In fact, the above is not very accurate. There is no need to maintain the maximum value on the left of the left pointer and the maximum value on the right of the right pointer, although it does not affect the result, because the maximum value represents the maximum height, and the width continues to decrease. To simplify:

/**
 * @param {number[]} height
 * @return {number}
 */
var maxArea = function(height) {
    
    
    let left=0, right=height.length-1, ans=0;
    while(left<=right){
    
    
        let lmax = height[left], rmax = height[right];

        if(lmax <= rmax){
    
    
            ans = Math.max(ans, lmax * (right-left))
            // while(left<=right && lmax >= height[left]) left++
            left++
        }else{
    
    
            ans = Math.max(ans, rmax * (right-left))
            // while(left<=right && rmax >= height[right]) right--
            right--
        }
    }
    return ans;
};

insert image description here

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324134369&siteId=291194637