[Leetcode] [Tutorial] Double pointers


283. Moving zeros

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

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

Solution

class Solution:
    def moveZeroes(self, nums: List[int]) -> None:
        slow, fast = 0, 0
        while fast < len(nums):
            if nums[fast] != 0:
                nums[slow], nums[fast] = nums[fast], nums[slow]
                slow += 1
            fast += 1    

15. Sum of three numbers

Given an integer array nums, determine whether there is a triplet [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 non-duplicate triples that sum to 0.

Note: Answers cannot contain duplicate triples.

Example:
Input: nums = [-1,0,1,2,-1,-4]
Output: [[-1,-1,2],[-1,0,1]]
Note that the order of the output is The order of the triples is not important.

Solution

Move the pointer of the shorter column toward the center each time because moving the taller column does not increase the water capacity.

class Solution:
    def threeSum(self, nums: List[int]) -> List[List[int]]:
        res= []
        nums.sort()
        for i in range(len(nums) - 2):
            if nums[i] > 0:
                break

            left, right = i + 1, len(nums) - 1
            while left < right:
                s = nums[i] + nums[left] + nums[right]
                if s > 0:
                    right -= 1
                elif s < 0:
                    left += 1
                else:
                    if [nums[i], nums[left], nums[right]] not in res:
                        res.append([nums[i], nums[left], nums[right]])
                    left += 1
        return res

If you use if [nums[i], nums[left], nums[right]] not in res: every time you find a triple to avoid duplication, the efficiency is low. We can:

  • When a solution is found, make sure that the numbers pointed to by the left and right pointers are different in the next iteration to avoid duplicate triples. This means that after finding the solution, we not only need to move the left or right pointers, but we also need to make sure they no longer point to the same number.

  • Add a check for fixed point i to skip duplicate values. This is a very important step because if you don't do it, you may end up with duplicate triples in the result, even if your double pointer handling is correct.

class Solution:
    def threeSum(self, nums: List[int]) -> List[List[int]]:
        res = []
        nums.sort()

        for i in range(len(nums) - 2):
            if nums[i] > 0:
                break
            # 跳过重复的数
            if i > 0 and nums[i] == nums[i - 1]:
                continue

            left, right = i + 1, len(nums) - 1
            while left < right:
                s = nums[i] + nums[left] + nums[right]

                if s > 0:
                    right -= 1
                elif s < 0:
                    left += 1
                else:
                    res.append([nums[i], nums[left], nums[right]])
                    # 跳过重复的数
                    while left < right and nums[left] == nums[left + 1]:
                        left += 1
                    while left < right and nums[right] == nums[right - 1]:
                        right -= 1
                    left += 1
                    right -= 1

        return res

11. The container that holds the most water

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 the two lines such that the container they form with the x-axis can hold the most water.
Returns the maximum amount of water the container can store.

Example:
Input: [1,8,6,2,5,4,8,3,7]
Output: 49

Solution

class Solution:
    def maxArea(self, height: List[int]) -> int:
        left, right = 0, len(height) - 1
        max_area = 0
        while left <= right:
            if height[left] < height[right]:
                max_area = max(max_area, (right - left) * height[left])
                left += 1
            else:
                max_area = max(max_area, (right - left) * height[right])
                right -= 1
        return max_area

42. Catching rainwater

Given n non-negative integers representing the height map of each column with a width of 1, calculate how much rainwater the columns arranged in this way can catch after it rains.

Example:
Input: height = [0,1,0,2,1,0,1,3,2,1,2,1]
Output: 6

Solution

The simple approach is to scan left and right for each position in the height array and record the maximum height on the left and right, and then take the minimum value between the two. The difference from the current height is the position that can be connected. amount of rain.

class Solution:
    def trap(self, height: List[int]) -> int:
        if not height:
            return 0
            
        n = len(height)
        rain = 0
        
        for i in range(n):
            max_left, max_right = 0, 0
            left, right = i-1, i+1
            while left >= 0:
                max_left = max(height[left], max_left)
                left -= 1
            while right < n:
                max_right = max(height[right], max_right)
                right += 1
            rain += max(0, min(max_left, max_right) - height[i])

        return rain

It should be noted that we need to ensure that min(max_left, max_right) is greater than the current height before subtracting the current height.

Now we use two arrays max_left and max_right of length n. For 0≤i<n, max_left represents the maximum height of subscript i and the position to its left, and max_right represents the height of subscript i and its position to its right. For the maximum height, the dynamic programming method is used to traverse the array height forward to obtain the value of each element of the array max_left, and to traverse the array height in the reverse direction to obtain the value of each element of the array max_right.

class Solution:
    def trap(self, height: List[int]) -> int:
        if not height:
            return 0
        
        n = len(height) 
        max_left, max_right = [0] * n, [0] * n
        max_left[0] = height[0]
        max_right[n - 1] = height[n - 1]

        for i in range(1, n):
            max_left[i] = max(max_left[i - 1], height[i])

        max_right = [0] * (n - 1) + [height[n - 1]]
        for i in range(n - 2, -1, -1):
            max_right[i] = max(max_right[i + 1], height[i])

        rain = sum(min(max_left[i], max_right[i]) - height[i] for i in range(n))
        return rain

In this solution, I used two different loops to get the max_left and max_right values ​​because the two arrays start at different positions and traverse in different directions.

If we can do it and calculate the rain at a certain position every time after calculating max_left on the left and max_right on the right, we can use the double pointer method to implement a time complexity of O(n) and space complexity. It is an O(1) algorithm.

class Solution:
    def trap(self, height: List[int]) -> int:
        if not height:
            return 0
        
        n = len(height)
        left, right = 0, n-1
        max_left, max_right = 0, 0
        rain = 0

        while left < right:
            max_left = max(max_left, height[left])
            max_right = max(max_right, height[right])
            if height[left] <= height[right]:
                rain += max_left - height[left]
                left += 1
            else:
                rain += max_right - height[right]
                right -= 1
        return rain

If height[left] < height[right], then for the column pointed by left, there must be a column on the right whose height is greater than or equal to height[right] (that is, right_max must be greater than or equal to height[left]). Therefore, we can calculate the amount of rainwater that the column pointed to left can receive, and then move left one position to the right. If height[left] >= height[right], similarly we can calculate the amount of rainwater that the column pointed by right can receive, and then move right one position to the left.

Guess you like

Origin blog.csdn.net/weixin_45427144/article/details/131264117