Double pointer algorithm (1)

Table of contents

move zero

carbon zero

happy number

The container that holds the most water

Double pointers combined with monotonicity

number of valid triangles

Find two items whose total price is the target value

Sum of two numbers Ⅱ - Input ordered array 


The double-pointer algorithm is an algorithm that solves the problem by defining two pointers to continuously move in one direction. However, the double pointer algorithm is an abstract ideological concept that can be used to solve problems such as array division and array blocking.

It usually does not really define two pointers. For example, in vectors and strings, subscripts are often used to act as pointers.

move zero

Light link:Move zero

Question: Given an array nums, write a function to move all 0 to the end of the array while maintaining the relative order of non-zero elements.

Please note that the array must be operated on in place without copying the array.

The meaning of the question: It is very clear that all non-zero elements are moved to the front of the array, and the zeros in the array are placed at the back of the array.

Idea: Define two 'pointers' cur and dest. The cur pointer is used to scan and traverse the array from left to right, always pointing to the last element scanned, and the dest pointer always points to the last non-zero position in the traversed array range. .

Specific method: define cur as 0 and dest as -1 (because we don’t know whether the first position needs to be exchanged). The cur pointer scans the array from left to right. If it encounters an element equal to 0, it will be skipped directly. If it encounters an element that is not equal to zero, it will be skipped directly. element, first add 1 to the position of the dest pointer, and then exchange the values ​​of the cur and dest positions, and then move the two pointers back one bit... This cycle continues until cur scans to the last bit of the array.

At this time, the array is divided into two parts, because dest points to the last non-zero position in the traversed array range, and the scan has ended, so the dest pointer points to the last non-zero position, cur The pointer points to the last position of the array, and the numbers between the two pointers are all zeros after movement.

Detailed code explanation (core code pattern)

class Solution {
public:
    void moveZeroes(vector<int>& nums) {
        int cur=0,dest=-1;
        while(cur<nums.size())
        {
            if(nums[cur]==0)
                cur++;
            else
            {
                dest++;
                swap(nums[dest],nums[cur]);
                cur++;
            }
        }
    }
};

carbon zero

Light link:Rewrite zero

Question: Given a fixed-length integer array arr , please copy every zero that appears in the array and shift the remaining elements to the right.

Note: Please do not write elements beyond the length of the array. Please make the above modifications to the input array  in place  and do not return anything from the function.

Idea: First copy the array according to the rules according to the 'off-site' operation, and then optimize it to the 'in-place' operation under double pointers.

Off-site operation method: two pointers cur and dest point to two arrays respectively, an original array and a new array with the same space as the original array. Use the cur pointer to traverse the original array. If a non-zero element is encountered, it will be copied sequentially in the new array. If a 0 element is encountered, it will be copied twice in a row in the new array.​ 

Optimization ideas for in-place operations: First use the idea of ​​‘off-site’ operations to find the positions of the final two pointer copy results, and complete the copy from front to back!

specific methods:

(1) Define cur as 0 and dest as -1. The cur pointer traverses the array. When it encounters a number that is not 0, dest moves forward one bit. When it encounters 0, dest moves forward two places. When dest reaches the last position of the array, the positions of cur and dest are from back to front. The position before starting copying.

(2) The cur pointer starts to move forward. When it encounters non-zero, dest copies the number and moves dest forward one bit; when it encounters 0, dest copies two zeros and moves forward two bits at the same time.... .When cur moves to the beginning of the array, the copying ends!

Detailed code explanation (core code pattern)

class Solution {
public:
    void duplicateZeros(vector<int>& arr) {
        int cur = 0, dest = -1;
        int n = arr.size();
        //第一步:找到复写的位置
        while (dest <n)
        {
            if (arr[cur] != 0)
                dest++;
            else if (arr[cur] == 0)
                dest += 2;
            if (dest >=n - 1)
                break;
            cur++;
        }
        //处理特殊情况
        if (dest==n)//dest指针越界,说明原数组倒数第二个位置为0
        {
            cur--;
            arr[n - 1] = 0;
            dest -= 2;
        }
        while (cur >= 0)
        {
            if (arr[cur] != 0)
            {
                arr[dest--] = arr[cur];
            }
            else if (arr[cur] == 0)
            {
                arr[dest--] = arr[cur];
                arr[dest--] = arr[cur];
            }
            cur--;
        }
    }
};

Note: When the penultimate position of the original array is 0, it needs to be processed separately after the loop ends, otherwise the array will be out of bounds!​ 

happy number

Link:Happy Number

Write an algorithm to determine whether a number n is a happy number.

``Kai 乐数'' Fixed price:

  • For a positive integer, each time the number is replaced by the sum of the squares of its digits at each position.
  • Then repeat this process until the number becomes 1, or it may be infinite loop but it never reaches 1.
  • If the result of this process  is  1, then this number is the happy number.

as a result n is happy number return true ; not, Turn around false .

Idea: The second point in the definition of happy number is very important, ‘repeat this process until the number becomes 1, or it may be an infinite loop but it never reaches 1’. So in this problem, each step of the operation can be regarded as the linked list moving forward. In fact, it can be abstracted into a linked list loop problem, and then use 'fast and slow pointers' to solve it.

The fast pointer here calculates the sum of squares for each bit and then calculates the sum of squares. The slow pointer only calculates the sum of squares once... This operation is continued. Since this number will eventually 'loop', then it becomes Is it a question of looping into 1 or looping over multiple other numbers?

When the fast pointer and the slow pointer meet (are equal), determine whether the number is 1. If it is 1, the number n is a happy number, otherwise it is not.

Detailed code explanation (core code pattern)

class Solution {
public:
    int Sumbit(int n)
    {
        int sum = 0;
        while(n)
        {
            int x = n % 10;
            sum += x*x;
            n /= 10;
        }
        return sum;
    }
    bool isHappy(int n) {
        //快慢指针
        int fast = n,slow = n;
        do
        {
            slow = Sumbit(slow);
            fast = Sumbit(Sumbit(fast));    
        }while(fast != slow);
        if(fast == 1)
            return true;
        else
            return false;
    }
};

Both the fast pointer and the slow pointer are initially equal to this number n. Define a function that calculates the sum of the squares of each bit: the slow pointer is called once, and the fast pointer is called twice. Then use the do...while loop to find the next value where the fast and slow pointers are equal, and determine whether this value is equal to 1.

The container that holds the most water

Close link:The container that holds the most water

Given an integer array of length n height . There are n vertical lines, and the two endpoints of the i line are (i, 0) and (i, height[i]) .

Find two of the lines so that the container formed by them and the x axis can hold the most water.

Returns the maximum amount of water the container can store.

Note:You cannot tilt the container.

Idea: The maximum height of the container that can hold water is determined by the lowest pillars on both sides! First calculate the volume of water starting from both sides and set it to Max. Use the double pointers to move from both sides to the middle, and the pointer on the lower side moves to the middle, and recalculates the capacity. If the new capacity is greater than the initial Max, update the value of Max. When the two pointers meet, the value of Max is the maximum value of water that the container can hold.

Detailed code explanation (core code pattern)

class Solution {
public:
    int V(vector<int>& height , int x , int y)
    {
        return min(height[x],height[y]) * (y-x);
    }
    int maxArea(vector<int>& height) {
        int left = 0, right = height.size()-1;
        int Max = 0;
        while(left != right)
        {
            int v = V(height,left,right);
            Max = max(v,Max);
            if(height[left] < height[right])
            {
                left++;
            }   
            else
                right--;
        }
        return Max;
    }
};

Double pointers combined with monotonicity

number of valid triangles

Light link:Number of valid triangles

Given an array containing non-negative integers nums , return the number of triples that can form three sides of a triangle.

Premise: In a set of numbers, if the sum of two smaller numbers is greater than the larger number, a triangle can be formed (the inference is that a set of numbers in which the sum of any three sides is greater than the third side can form a triangle)

Idea: Sort first, ensuring not to sort in descending order. Starting from the right side of the array, fix the largest number, use double pointers (one pointer is on the far left, and the other pointer is on the left side of the fixed number) to determine the number of triangles that can be formed in the left half of the fixed number, and then move to Update the fixed number to the left and repeat the above steps until there are only two numbers in the left half of the interval and the loop ends.

Determine the number of triangles that can be formed in the left half of the interval: assuming the fixed number position is tmp, then the right position is tmp -1 and the value of the left position is 0. Determine the size of the result after adding two position numbers and the fixed number:If it is greater than two pointers All numbers between [ left , right ) can form triangles with right and tmp, then the number of triangles that can be formed will increase by ( right - left )< a i=5>;If it is less than or equal to, it means that the value on the left side is not large enough, add 1 to the left pointer, and repeat the above comparison process. When the left pointer and the right pointer meet, or the numbers of the two are greater than the number of the tmp position, the current cycle ends, and the position of the fixed number is updated to continue the above process.

Detailed code explanation (core code pattern)

class Solution {
public:
    int triangleNumber(vector<int>& nums) {
        //只要两个小数相加大于大数,就能构成三角形
        sort(nums.begin(),nums.end());//先排序
        size_t sum = 0;
        //外层循环,固定一个最大的数
        for(int tmp = nums.size()-1; tmp >= 2; tmp --)
        {
            int right = tmp-1;
            int left = 0;
            //利用双指针算法
            while(right != left)
            {
                if(nums[left] + nums[right] > nums[tmp])
                {
                    sum += (right-left);
                    right--;
                }
                else
                {
                    left++;
                }
            }
        }
        return sum;
    }
};

Find two items whose total price is the target value

Sum of two numbers Ⅱ - Input ordered array 

These two questions are an idea and a return number. One goes back down. But they are all double-pointer ideas and use monotonicity to solve problems!

Set two pointers, one on the left and one on the right. Because the array is ordered, the left is the smallest and the right is the largest. The two pointers move to the middle and are determined based on the relationship between the sum and the target value. When the pointer moves, the position where the last two pointers stay is the position where the sum of the two numbers is equal to the target value.​ 

Detailed explanation of finding two product codes whose total price is the target value (core code mode)

class Solution {
public:
    vector<int> twoSum(vector<int>& price, int target) {
        vector<int> v1;
        int left = 0,right = price.size() - 1;
        while(left < right)
        {
            if(price[left] + price[right] == target)
            {
                v1.push_back(price[left]);
                v1.push_back(price[right]);
                break;
            }
            if(price[left] + price[right] < target)
            {
                left++;
            }
            else
            {
                right--;
            }
        }
        return v1;
    }
};

Sum of two numbers Ⅱ - Input ordered array (core code mode) 

class Solution {
public:
    vector<int> twoSum(vector<int>& numbers, int target) {
        vector<int> v1;
        int left = 0,right = numbers.size()-1;
        while(left < right)
        {
            if(numbers[left]+numbers[right]==target)
            {
                v1.push_back(left+1);
                v1.push_back(right+1);
                break;
            }
            if(numbers[left] + numbers[right]>target)
            {
                right--;
            }
            else
            {
                left++;
            }
        }
        return v1;
    }
};

Guess you like

Origin blog.csdn.net/zyb___/article/details/134966304