leetcode classification question: double pointers based on arrays (3. Sum of elements of ordered arrays)

1. It is a bit like the premise of "leetcode classification question: Binary Search (1. Type based on index (definition domain))". The array is sorted, and then the goal of solving is the sum of elements, not finding a certain The first time an element is greater than or equal to the index position of the array element
2. A slightly more complicated question type is to solve triples, quadruples, etc., just like "leetcode classification test questions: Hash Table (1) , a simple sum of two numbers)" mentioned in "The problem of summing elements of this type of array, the difficulty lies in the goal of solving it . Here we need to return triples, quadruples, etc. composed of the values ​​of the answer, so we need to consider The problem of deduplication of answers ; additionally, you can consider adding special case judgments (of course, the code can pass smoothly without adding this). You need to pay attention to whether the target value is a negative number or a non-negative number, conduct a classification discussion, and finally summarize the problem-solving ideas for this type of problem. : Sorting + double pointers + deduplication of answers + judgment of special circumstances (can be omitted)

167. Sum of Two Numbers II - Input ordered array

1. This article summarizes the classic question types. Pay attention to the details: the subscripts start from 1.
2. This question is the basic question for the following questions.

from typing import List
'''
167. 两数之和 II - 输入有序数组
给你一个下标从 1 开始的整数数组numbers ,该数组已按 非递减顺序排列 ,请你从数组中找出满足相加之和等于目标数target 的两个数。
如果设这两个数分别是 numbers[index1] 和 numbers[index2] ,则 1 <= index1 < index2 <= numbers.length 。
以长度为 2 的整数数组 [index1, index2] 的形式返回这两个整数的下标 index1 和 index2。
你可以假设每个输入 只对应唯一的答案 ,而且你 不可以 重复使用相同的元素。
你所设计的解决方案必须只使用常量级的额外空间。
示例 1:
    输入:numbers = [2,7,11,15], target = 9
    输出:[1,2]
    解释:2 与 7 之和等于目标数 9 。因此 index1 = 1, index2 = 2 。返回 [1, 2] 。
题眼:两数之和+有序
思路:有序问题使用双指针最好
'''


class Solution:
    def twoSum(self, numbers: List[int], target: int) -> List[int]:
        left, right = 0, len(numbers) - 1
        while left < right:  # 答案的下标不能重复
            if numbers[left] + numbers[right] == target:
                return [left+1, right+1]  # 下标从1开始
            elif numbers[left] + numbers[right] > target:
                right -= 1
            else:
                left += 1


if __name__ == "__main__":
    obj = Solution()
    while True:
        try:
            in_line = input().strip().split('=')
            nums = [int(n) for n in in_line[1].split(']')[0].split('[')[1].split(',')]
            target = int(in_line[2].strip())
            print(obj.twoSum(nums, target))
        except EOFError:
            break

15. Sum of three numbers

Idea: Different from returning the subscript, here is the return value ; an extension of "167. Sum of Two Numbers II - Input Ordered Array" + the answer to the triple should add deduplication logic at each position ;
additional considerations can be made Plus special case judgment (you need to pay attention to whether the target value is negative or non-negative)

from typing import List
'''
15. 三数之和
给你一个整数数组 nums ,判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i != j、i != k 且 j != k ,同时还满足 nums[i] + nums[j] + nums[k] == 0 。
请返回所有和为 0 且不重复的三元组。注意:答案中不可以包含重复的三元组。
示例 1:
    输入: nums = [-1,0,1,2,-1,-4]
    输出: [[-1,-1,2],[-1,0,1]]
    解释: 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 。
          不同的三元组是 [-1,0,1] 和 [-1,-1,2] 。 注意,输出的顺序和三元组的顺序并不重要。
题眼:这种题目的复杂程度取决于求解目标:求值构成的三元组 且不能重复
思路:不同于返回下标,这里是返回值;"167. 两数之和 II - 输入有序数组"的扩展 + 对三元组的答案在每个位置都要添加去重逻辑;
额外可以考虑加上 特殊情况的判断(需要注意target值为负数还是非负数)
'''


class Solution:
    def threeSum(self, nums: List[int]) -> List[List[int]]:
        # 这种题目的复杂程度取决于求解目标:求值构成的三元组 且不能重复
        result = []
        nums.sort()
        for i in range(len(nums) - 2):
            # 特殊情况判断:三元组答案的第一个元素大于target,不必再求解后续位置元素
            if nums[i] > 0:
                break
            # 三元组答案的第一个元素去重
            if i > 0 and nums[i] == nums[i - 1]:
                continue
            # "167. 两数之和 II - 输入有序数组"的扩展,查找剩余二元组,target值为-nums[i];但要注意剩余二元组的去重
            left, right = i + 1, len(nums) - 1
            while left < right:
                # 双指针遍历过程
                if nums[left] + nums[right] > -nums[i]:
                    right -= 1
                elif nums[left] + nums[right] < -nums[i]:
                    left += 1
                else:
                    result.append([nums[i], nums[left], nums[right]])
                    left += 1
                    right -= 1
                    # 三元组答案的第二、三个元素去重
                    while left < right and nums[left] == nums[left - 1]:
                        left += 1
                    while left < right and nums[right] == nums[right + 1]:
                        right -= 1
        return result


if __name__ == "__main__":
    obj = Solution()
    while True:
        try:
            nums = [int(n) for n in input().strip().split('[')[1][:-1].split(',')]
            print(nums)
            print(obj.threeSum(nums))
        except EOFError:
            break

18. Sum of four numbers

Idea: Extension of "15. Sum of Three Numbers" + Add deduplication logic to each position of the answer to the triplet ;
additionally, you can consider adding special case judgments ( you need to pay attention to whether the target value is a negative number or a non-negative number )

from typing import List
'''
18. 四数之和
给你一个由n个整数组成的数组nums,和一个目标 target。请你找出并返回满足下述全部条件且不重复的四元组[nums[a], nums[b], nums[c], nums[d]]
(若两个四元组元素一一对应,则认为两个四元组重复):
0 <= a, b, c, d< n
a、b、c 和 d 互不相同
nums[a] + nums[b] + nums[c] + nums[d] == target
示例 1:
    输入: nums = [1,0,-1,0,-2,2], target = 0
    输出: [[-2,-1,1,2],[-2,0,0,2],[-1,0,0,1]]
题眼:这种题目的复杂程度取决于求解目标:求值构成的四元组 且不能重复
思路:“15. 三数之和”的扩展 + 对三元组的答案在每个位置都要添加去重逻辑;
额外可以考虑加上 特殊情况的判断(需要注意target值为负数还是非负数)
'''


class Solution:
    def fourSum(self, nums: List[int], target: int) -> List[List[int]]:
        result = []
        # 情况1、数组长度小于4,直接返回[]
        if len(nums) < 4:
            return result
        nums.sort()
        for i in range(len(nums) - 3):
            # 特殊情况判断:四元组答案的第一个元素情况(需要注意target值为负数还是非负数)
            if target >= 0 and nums[i] > target or target < 0 and nums[i] >= 0:
                break
            # 四元组答案的第一个元素去重
            if i > 0 and nums[i] == nums[i - 1]:
                continue
            # 寻找剩余三元组的过程
            for j in range(i + 1, len(nums) - 2):
                # 特殊情况判断:四元组答案的第一个元素情况(需要注意target值为负数还是非负数)
                if target >= 0 and nums[i] + nums[j] > target or target < 0 and nums[i] + nums[j] >= 0:
                    break
                # 四元组答案的第二个元素去重
                if j > i + 1 and nums[j] == nums[j - 1]:
                    continue
                # 寻找剩余二元组的过程
                left, right = j + 1, len(nums) - 1
                while left < right:
                    # 双指针遍历过程
                    if nums[left] + nums[right] < target - nums[i] - nums[j]:
                        left += 1
                    elif nums[left] + nums[right] > target - nums[i] - nums[j]:
                        right -= 1
                    else:
                        result.append([nums[i], nums[j], nums[left], nums[right]])
                        left += 1
                        right -= 1
                        # 四元组答案的第三、四个元素去重
                        while left < right and nums[left] == nums[left - 1]:
                            left += 1
                        while left < right and nums[right] == nums[right + 1]:
                            right -= 1
        return result


if __name__ == "__main__":
    obj = Solution()
    while True:
        try:
            in_line = input().strip().split('=')
            nums = [int(n) for n in in_line[1].split(']')[0].split('[')[1].split(',')]
            target = int(in_line[2].strip())
            print(nums, target)
            print(obj.fourSum(nums, target))
        except EOFError:
            break

16. The sum of the nearest three numbers

Idea: The expansion of "167. Sum of Two Numbers II - Input Ordered Array" seems to have become simpler, because there is no need to consider duplicate answers.

from typing import List
'''
16. 最接近的三数之和
给你一个长度为 n 的整数数组nums和 一个目标值target。请你从 nums 中选出三个整数,使它们的和与target最接近。
返回这三个数的和。
假定每组输入只存在恰好一个解。
示例 1:
    输入:nums = [-1,2,1,-4], target = 1
    输出:2
    解释:与 target 最接近的和是 2 (-1 + 2 + 1 = 2) 。
题眼:三数之和
思路:"167. 两数之和 II - 输入有序数组"的扩展
'''


class Solution:
    def threeSumClosest(self, nums: List[int], target: int) -> int:
        nums.sort()
        result = nums[0] + nums[1] + nums[2]  # 将result初始值设定为排序后的前三个元素之和 或者 设置为float('inf)
        for i in range(len(nums) - 2):
            # "167. 两数之和 II - 输入有序数组"的扩展
            left, right = i + 1, len(nums) - 1
            while left < right:
                s = nums[i] + nums[left] + nums[right]
                if abs(s - target) < abs(result - target):
                    result = s
                if s == target:
                    return result
                elif s > target:  # 更接近的加和 需要变小,更新右指针
                    right -= 1
                else:    # 更接近的加和 需要变大,更新左指针
                    left += 1
        return result


if __name__ == "__main__":
    while True:
        try:
            in_line = input().strip().split('=')
            nums = [int(n) for n in in_line[1].split('[')[1].split(']')[0].split(',')]
            target = int(in_line[2])
            print(nums, target)
        except EOFError:
            break

259. Sum of three smaller numbers

Idea: An expansion of "16. The closest sum of three numbers", the solution goal becomes the number of triples, and there is no need to consider the problem of deduplication.

from typing import List
'''
259. 较小的三数之和
给定一个长度为 n 的整数数组和一个目标值 target,寻找能够使条件 nums[i] + nums[j] + nums[k] < target 
成立的三元组  i, j, k 个数(0 <= i < j < k < n)。
示例 1:
    输入: nums = [-2,0,1,3], target = 2
    输出: 2 
    解释: 因为一共有两个三元组满足累加和小于 2:
        [-2,0,1]
        [-2,0,3]
题眼:三数之和
思路:"16. 最接近的三数之和"的扩展,求解目标变成了三元组的个数,不考虑去重的问题
'''


class Solution:
    def threeSumSmaller(self, nums: List[int], target: int) -> int:
        nums.sort()
        result = 0
        for i in range(len(nums) - 2):
            # "167. 两数之和 II - 输入有序数组"的扩展
            left, right = i + 1, len(nums) - 1
            while left < right:
                s = nums[i] + nums[left] + nums[right]
                if s < target:
                    result += right - left  # (left, right]区间的所有数值全部满足
                    left += 1
                else:
                    right -= 1
        return result


if __name__ == "__main__":
    obj = Solution()
    while True:
        try:
            in_line = input().strip().split('=')
            nums = [int(n) for n in in_line[1].split('[')[1].split(']')[0].split(',')]
            target = int(in_line[2])
            print(obj.threeSumSmaller(nums, target))
        except EOFError:
            break

Guess you like

Origin blog.csdn.net/qq_39975984/article/details/132577478