【Algorithm Series】Double Pointer

insert image description here

foreword

Friends, hello everyone, starting today I will continue to update articles about algorithms for you. If you are interested in algorithms, you are welcome to subscribe to my algorithm column.

What is Double Pointer Arithmetic

Two Pointers Algorithm (Two Pointers Algorithm) is a commonly used algorithmic trick, usually used for problems in arrays, linked lists, or other linear data structures. The algorithm uses two pointers to iterate, search, or compare data structures to solve a specific problem.

In double pointer arithmetic, two pointers are usually used called "fast pointer" and "slow pointer". The fast pointer and slow pointer usually start at the same position, and then move the pointer in different steps according to the requirements of the problem. The fast hand may move multiple positions at a time, while the slow hand moves only one position at a time.

There are several common applications of double pointer arithmetic:

  1. Two Pointers Approach : The fast pointer starts from the head of the array, the slow pointer starts from the end of the array, and the two move toward the middle until they meet or cross. This approach is often used for problems like searching, summing, etc. in sorted arrays.

  2. Fast and Slow Pointers : Fast pointers and slow pointers traverse the linked list at different speeds. This method is usually used to solve problems such as ring detection in linked lists, finding the midpoint of linked lists, and inversion of linked lists.

  3. Sliding Window (Sliding Window): Use two pointers to define a fixed-size window on an array or string, and then move the window's starting or ending position as the question requires. This approach is often used for substring or subarray problems within strings or arrays.

The advantage of double-pointer arithmetic is that it generally has a low time complexity and requires only a constant amount of extra space when traversing the data. It can effectively reduce the time complexity of the problem, and is often used to solve some problems related to arrays and linked lists.

1. Moving Zero

https://leetcode.cn/problems/move-zeroes/

1.1 Topic Requirements

Given an array nums, write a function to move all 0s to the end of the array while maintaining the relative order of the nonzero elements.

Note that arrays must be manipulated in-place without copying them.

Example 1:

Input: nums = [0,1,0,3,12]
Output: [1,3,12,0,0]

Example 2:

Input: nums = [0]
Output: [0]

class Solution {
    
    
    public void moveZeroes(int[] nums) {
    
    

    }
}

1.2 Ideas for doing the questions

The purpose of this topic is to move all the zeros in the array to the right part of the non-zero numbers, and we can just use double pointers to divide an array into three parts, the first part is the non-zero part, the second part is the number 0, The third part is the part to be moved.

insert image description here
And these three parts, we use two pointers slow and fast to maintain, when the number pointed to by fast is not 0, it is exchanged with the number pointed to by slow. In this way, it can be guaranteed that the left side of slow is the non-zero number after the movement, the number between slow and fast is the 0 number after the movement, and the right side of fast is the part to be moved.

insert image description here

1.3 Java code implementation

class Solution {
    
    
    public void moveZeroes(int[] nums) {
    
    
        int slow = -1;
        int fast = 0;
        int n = nums.length;
        while(fast < n) {
    
    
            if(nums[fast] != 0) {
    
    
                int tmp = nums[++slow];
                nums[slow] = nums[fast];
                nums[fast] = tmp;
            }
            fast++;
        }
    }
}

insert image description here

2. Overwrite zero

https://leetcode.cn/problems/duplicate-zeros/

2.1 Topic Requirements

Given a fixed-length integer array arr, please overwrite every zero that appears in the array, and shift the rest of the elements to the right.

Note: Please do not write elements beyond the length of the array. Please do the above modification in-place on the input array and don't return anything from the function.

Example 1:

Input: arr = [1,0,2,3,0,4,5,0]
Output: [1,0,0,2,3,0,0,4]
Explanation: After calling the function, the input array will be is modified to: [1,0,0,2,3,0,0,4]

Example 2:

Input: arr = [1,2,3]
Output: [1,2,3]
Explanation: After calling the function, the input array will be modified to: [1,2,3]

class Solution {
    
    
    public void duplicateZeros(int[] arr) {
    
    

    }
}

2.2 Ideas for doing the questions

The first thing many people think about when they get this question is to use double pointers from front to back. When encountering 0, write 0 twice, but if this is the case, the subsequent numbers will be overwritten, which will be very troublesome. We might as well change the way of thinking: we can first find the last number of the array after overwriting, and then write the data from the back to the front. When encountering 0, write it twice, and write it once if it is not 0.

So doing this topic is roughly divided into two steps: 1. Find the last number of the array after overwriting 2. Write data from back to front

insert image description here

insert image description here

2.3 Java code implementation

class Solution {
    
    
    public void duplicateZeros(int[] arr) {
    
    
        int slow = 0;
        int fast = -1;
        int n = arr.length;
        //1.找到复写之后数组的最后一个数字
        while(fast < n-1) {
    
    
            if(arr[slow] != 0) fast++;
            else fast += 2;
            if(fast >= n-1) break;
            slow++;
        }

        //2.调整边界
        //当fast=n的时候,说明slow所指的最后一个数字为0
        if(fast == n) {
    
    
            arr[n-1] = 0;
            fast = n-2;
            slow--;
        }

        //3.从后往前写入数据
        while(slow >= 0) {
    
    
            if(arr[slow] != 0) {
    
    
                arr[fast--] = arr[slow--];
            }else {
    
    
                arr[fast--] = 0;
                arr[fast--] = 0;
                slow--;
            }
        }
    }
}

insert image description here

3. Happy Number

https://leetcode.cn/problems/happy-number/

3.1 Topic Requirements

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

"Happy Number" is defined as:

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

Returns true if n is a happy number; otherwise, returns false.

Example 1:

Input: n=19
Output: true
Explanation:
12+92=82
82+22=68
62+82=100
12+02+02=1

Example 2:

Input: n = 2
Output: false

class Solution {
    
    
    public boolean isHappy(int n) {
    
    
    
    }
}

3.2 Ideas for doing the questions

To judge whether it is a happy number, we need to know that when we perform the operation of summing the squares of each number, a ring will eventually be formed.
insert image description here
insert image description here
Since all will form a ring, we only need to use the speed pointer to find the ring, and then judge whether the ring is 1. If it is a happy number, it will form a ring between 1->1, and the non-happy number is not necessarily up.

3.3 Java code implementation

class Solution {
    
    
    private int bitSum(int n) {
    
    
        int sum = 0;
        while(n != 0) {
    
    
            int tmp = n % 10;
            sum += tmp*tmp;
            n /= 10;
        }
        
        return sum;
    }

    public boolean isHappy(int n) {
    
    
        int slow = n;
        int fast = bitSum(n); //这里先将快指针进行一次求和操作,防止刚开始就相等了
        //slow每次进行一次操作,fast一次进行两次操作
        while(slow != fast) {
    
    
            slow = bitSum(slow);
            fast = bitSum(bitSum(fast));
            if(slow == fast) break;
        }

        return slow == 1;
    }
}

insert image description here

4. The container that holds the most water

https://leetcode.cn/problems/container-with-most-water/

4.1 Topic Requirements

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

Find two of these lines such that, together with the x-axis, they form a container that holds the most water.

Returns the maximum amount of water the container can store.

Instructions: You cannot tilt the container.

Example 1:
insert image description here

Input: [1,8,6,2,5,4,8,3,7]
Output: 49
Explanation: The vertical line in the figure represents the input array [1,8,6,2,5,4,8,3, 7]. In this case, the maximum amount of water the container can hold (shown in blue) is 49.

Example 2:

Input: height = [1,1]
Output: 1

class Solution {
    
    
    public int maxArea(int[] height) {
    
    
    
    }
}

4.2 Ideas for doing the questions

The capacity of the container is related to the product of x y, so we need to consider both x and y, but there is no guarantee that x and y are the largest, we can only guarantee that either x or y is the largest, and then find When x y is the largest. So here we first ensure that x is the largest, the left pointer points to the far left, and the right pointer points to the far right, and then find the largest product of x*y.

The volume is calculated like this (right - left) * min(height[left],height[right]). Set a variable to store the volume, and keep updating this variable to ensure that this variable stores the data with the largest volume. The values ​​of left and right also need to be constantly changed, and the pointers pointed to by left and right with smaller data need to be replaced, because what we are looking for is the data with the largest product.

  • The width of the container must become smaller.
  • Since the left border is smaller, it determines the height of the water. If the left boundary is changed, the new height of the water surface is uncertain, but it must not exceed the height of the column on the right, so the volume of the container may increase.
  • If you change the right border, no matter where the right border moves, the height of the new water surface must not exceed the left border, that is, it will not exceed the current height of the water surface, but because the width of the container is reduced, so The volume of the container will definitely decrease

4.3 Java code implementation

class Solution {
    
    
    public int maxArea(int[] height) {
    
    
        int n = height.length;
        int left = 0;
        int right = n-1;
        int ret = 0;  //用来存储体积
        while(left < right) {
    
    
            int v = (right - left) * Math.min(height[left],height[right]);
            ret = Math.max(v,ret);
            if(height[left] < height[right]) left++;
            else right--;
        }

        return ret;
    }
}

insert image description here

5. Number of valid triangles

https://leetcode.cn/problems/valid-triangle-number/

5.1 Topic Requirements

Given an array nums containing non-negative integers, return the number of triples in which the three sides of a triangle can be formed.

Example 1:

Input: nums = [2,2,3,4]
Output: 3
Explanation: Valid combinations are:
2,3,4 (use first 2)
2,3,4 (use second 2)
2,2 ,3
Example 2:

Input: nums = [4,2,3,4]
Output: 4

class Solution {
    
    
    public int triangleNumber(int[] nums) {
    
    

    }
}

5.2 Ideas for doing the questions

Everyone should be familiar with the effective triangle: the sum of any two sides is greater than the third side, but do we really need to judge the combination of two pairs? In fact, it is not, only two shorter sides need to be judged The sum is greater than the longer side.

Now that we know that we only need to judge once to judge whether it is a valid triangle, we can first sort the array in ascending order, starting from the end of the array, using it as the longest side of the triangle, and then within the range of the previous array , the left pointer points to the far left of the front part, and the right pointer points to the far right, and the number of effective triangles is counted by moving the positions of left and right. If nums[left] + nums[right} > the longest side, then the sides from left to right - 1 and right and the longest side can be combined into a valid triangle; therefore, take this length as the longest The number of triangles on the side is right -left, then right–, continue the operation until left == right; if nums[left] + nums[right} < the longest side, you need to move the position of left until you meet Go to the position where nums[left] + nums[right} > the longest side, and then count the number of valid triangles.

insert image description here

5.3 Java code implementation

class Solution {
    
    
    public int triangleNumber(int[] nums) {
    
    
        Arrays.sort(nums);
        int sum = 0;
        for(int i = nums.length-1; i > 1; i--) {
    
    
            int left = 0;
            int right = i-1;
            while(left < right) {
    
    
                if(nums[left] + nums[right] > nums[i]) {
    
    
                    sum = sum + right - left;
                    right--;
                }else {
    
    
                    left++;
                }
            }
        }

        return sum;
    }
}

insert image description here

6. Two numbers whose sum is S

https://leetcode.cn/problems/he-wei-sde-liang-ge-shu-zi-lcof/

6.1 Topic Requirements

Input an array sorted in ascending order and a number s, find two numbers in the array such that their sum is exactly s. If the sum of multiple pairs of numbers is equal to s, just output any pair.

Example 1:

Input: nums = [2,7,11,15], target = 9
Output: [2,7] or [7,2]
Example 2:

Input: nums = [10,26,30,31,47,60], target = 40
Output: [10,30] or [30,10]

class Solution {
    
    
    public int[] twoSum(int[] nums, int target) {
    
    

    }
}

6.2 Ideas for doing the questions

The idea of ​​this topic is similar to the idea above. Use double pointers, left points to the leftmost of the array (that is, the minimum value), right points to the rightmost (maximum value) of the array, and then judges the relationship between nums[left] + nums[right] and target, if nums[left] + If nums[right] > target, adjust the value of right; if nums[left] + nums[right] < target, adjust the value of left, and if they are equal, save it.

6.3 Java code implementation

class Solution {
    
    
    public int[] twoSum(int[] nums, int target) {
    
    
        int left = 0;
        int right = nums.length-1;
        while(left < right) {
    
    
            int sum = nums[left] + nums[right];
            if(sum > target) {
    
    
                right--;
            }else if(sum < target) {
    
    
                left++;
            }else {
    
    
                return new int[]{
    
    nums[left],nums[right]};
            }
        }

        return new int[]{
    
    -1,-1};
    }
}

insert image description here

7. The sum of three numbers

https://leetcode.cn/problems/3sum/

7.1 Topic Requirements

Given an integer array nums, determine whether there is a triple [nums[i], nums[j], nums[k]] that satisfies i != j, i != k and j != k, and also satisfies nums[ i] + nums[j] + nums[k] == 0 . please

You return all triples that sum to 0 and are not duplicates.

Note: Duplicate triplets are not allowed in the answer.

Example 1:

Input: nums = [-1,0,1,2,-1,-4]
Output: [[-1,-1,2],[-1,0,1]]
Explanation:
nums[0] + nums [1] + nums[2] = (-1) + 0 + 1 = 0 .
nums[1] + nums[2] + nums[4] = 0 + 1 + (-1) = 0 .
nums[0] + nums[3] + nums[4] = (-1) + 2 + (-1) = 0 .
The different triples are [-1,0,1] and [-1,-1,2].
Note that the order of the output and the order of the triples is not important.

Example 2:

Input: nums = [0,1,1]
Output: []
Explanation: The only possible triple sum is not 0.
Example 3:

Input: nums = [0,0,0]
Output: [[0,0,0]]
Explanation: The only possible triple sum is 0.

class Solution {
    
    
    public List<List<Integer>> threeSum(int[] nums) {
    
    

    }
}

7.2 Ideas for doing the questions

When we know how to solve the problem of the sum of two numbers, it is actually very simple to find the sum of three values. Let us sort the array in ascending order and fix one number at a time, and then find the sum in the remaining array as target - nums [i], but is it really that simple? Pay attention to the question, the repeated triplet cannot appear in the answer, what is a repeated triplet, look at the first example, it is equal to the three numbers of target are (-1,0,1),(0,1, -1),(-1,2,-1) , but the final output is only [[-1,-1,2],[-1,0,1]], so the key to this question is to deduplicate On this issue, how should we de-duplicate it? When adjusting left, right and that fixed number, if the number pointed to is equal to the previous number, skip it.

insert image description here

7.3 Java code implementation

class Solution {
    
    
    public List<List<Integer>> threeSum(int[] nums) {
    
    
        List<List<Integer>> list = new ArrayList<>();
        Arrays.sort(nums);
        int n = nums.length;
        int i = 0;
        while(i < n && nums[i] <= 0) {
    
    
            int left = i + 1;
            int right = n - 1;
            int target = -nums[i];
            while(left < right) {
    
    
                int sum = nums[left] + nums[right];
                if(sum > target) {
    
    
                    right--;
                }else if(sum < target) {
    
    
                    left++;
                }else {
    
    
                    List<Integer> list1 = new ArrayList<>();
                    list1.add(nums[i]);
                    list1.add(nums[left]);
                    list1.add(nums[right]);
                    list.add(list1);
                    left++;
                    right--;
                    //去重并且防止越界
                    while(left < right && nums[left] == nums[left-1]) left++;
                    while(left < right && nums[right] == nums[right+1]) right--;
                }
            }
            i++;
            while(i < n && nums[i] <= 0 && nums[i] == nums[i-1]) i++;
        }
        return list;
    }
}

insert image description here

8. Sum of four numbers

https://leetcode.cn/problems/4sum/

8.1 Topic Requirements

You are given an array nums of n integers, and a target value target. Please find and return quadruples [nums[a], nums[b], nums[c], nums[d]] that meet all the following conditions and are not repeated (if two quadruple elements correspond one-to-one , the two quadruples are considered repeated):

0 <= a, b, c, d < n
a, b, c and d are different from each other
nums[a] + nums[b] + nums[c] + nums[d] == target
you can return in any order Answer.

Example 1:

Input: nums = [1,0,-1,0,-2,2], target = 0
Output: [[-2,-1,1,2],[-2,0,0,2],[ -1,0,0,1]]
Example 2:

Input: nums = [2,2,2,2,2], target = 8
Output: [[2,2,2,2]]

class Solution {
    
    
    public List<List<Integer>> fourSum(int[] nums, int target) {
    
    

    }
}

8.2 Ideas for doing the questions

This is the sum of the four numbers. If the sum of the previous two numbers and the sum of the three numbers can be done, this topic is also very simple. We only need to fix a number first, and then find the sum in the following array as target - nums[ The three numbers of i] will do, the only thing to pay attention to is deduplication. So I won't introduce too much about this topic, you can just look at the code.

8.3 Java code implementation

class Solution {
    
    
    public List<List<Integer>> fourSum(int[] nums, int target) {
    
    
        List<List<Integer>> list = new ArrayList<>();
        int i = 0;
        int n = nums.length;
        Arrays.sort(nums);
        while(i < n) {
    
    
            int j = i + 1;
            long tmp1 = target-nums[i];
            while(j < n) {
    
    
                int slow = j + 1;
                int fast = n-1;
                long tmp2 = tmp1 - nums[j];
                while(slow < fast) {
    
    
                    int sum = nums[slow] + nums[fast];
                    if(sum > tmp2) {
    
    
                        fast--;
                    }else if(sum < tmp2) {
    
    
                        slow++;
                    }else {
    
    
                        List<Integer> list1 = new ArrayList<>();
                        list1.add(nums[i]);
                        list1.add(nums[j]);
                        list1.add(nums[slow]);
                        list1.add(nums[fast]);
                        list.add(list1);
                        slow++;
                        fast--;
                        while(slow < fast && nums[slow] == nums[slow-1]) slow++;
                        while(slow < fast && nums[fast] == nums[fast+1]) fast--;
                    }
                }
                j++;
                while(j < n && nums[j] == nums[j-1]) j++;
            }
            i++;
            while(i < n && nums[i] == nums[i-1]) i++;
        }

        return list;
    }
}

insert image description here

Guess you like

Origin blog.csdn.net/m0_73888323/article/details/132341192