[Topic] Sum

Posted by 西维蜀黍的OJ Blog on 2023-10-26, Last Modified on 2025-03-25

解析

1. Two Sum

# brute force
# - time: O(n2)
# - space: O(1)
    def twoSum(self, nums: List[int], target: int) -> List[int]:
        for i in range(len(nums)):
            for j in range(i + 1, len(nums)):
                if nums[i] + nums[j] == target:
                    return [i, j]
        return []

# sort + 双指针
# - time: O(nlogn)
# - space: O(n)
   def twoSum(self, nums, target):
        """
        :type nums: List[int]
        :type target: int
        :rtype: List[int]
        """
        A = []  # 记录排序前,元素num 的原始索引(因为结果中需要返回原始索引)
        for i, num in enumerate(nums):
            A.append([num, i])

        A.sort()  # A 将按照每个二元组的第一个元素(即数值)从小到大排序
        i, j = 0, len(nums) - 1  # i 指向数组左端(最小值),j 指向数组右端(最大值)
        while i < j:
            cur = A[i][0] + A[j][0]
            if cur == target:
                return [A[i][1], A[j][1]]
            elif cur < target:
                i += 1
            else:
                j -= 1
        return []
      
# hashmap
# - time: O(n)
# - space: O(n)
    def twoSum(self, nums, target):
        """
        :type nums: List[int]
        :type target: int
        :rtype: List[int]
        """
        prevMap = {} # prevMap 中存储的都是可以被考虑的数字
        for i, v in enumerate(nums):
            diff = target - v
            if diff in prevMap:
                return [prevMap[diff], i]
            prevMap[v] = i

167. Two Sum II - Input Array Is Sorted

# brute force
#  - time: O(n^2)
#  - space: O(1)  
    def twoSum(self, numbers: List[int], target: int) -> List[int]:
        for i in range(len(numbers)):
            for j in range(i + 1, len(numbers)):
                if numbers[i] + numbers[j] == target:
                    return [i + 1, j + 1]
        return []
      
# 左右指针(双指针)
#  - time: O(n)
#  - space: O(1)  
    def twoSum(self, numbers, target):
        """
        :type numbers: List[int]
        :type target: int
        :rtype: List[int]
        """
        l, r = 0, len(numbers) - 1
        while l < r:
            cur_sum = numbers[l] + numbers[r]
            if cur_sum == target:
                return [l + 1, r + 1]
            elif cur_sum > target:
                r -= 1
            else:
                l += 1

ref

15 3Sum

  • 排序后,如何保证插入结果集的triplet不重复?
    • Approach 1: 用一个set来记录已经插入结果集的triplet,如果当前triplet已经存在于set中,那么就跳过该triplet
    • Approach 2:
      • 对于左边的指针,if (i > 0 && nums[i] == nums[i - 1]) continue;
        • 比如 [-2, -2, 0, 2] 的情况,如果不加这个判断,那么就会发生结果集中有两个重复的[-2, 0, 2] triplet 的情况
      • 对于中间的指针,while nums[m] == nums[m-1] m += 1
        • 比如 [-2, 0, 0, 2, 2] 的情况,如果不加这个判断,那么会出现结果集中有两个重复的[-2, 0, 2] triplet的情况
# burte force
#  - time: O(n3)
#  - space: O(n) // 解决重复 triplet 的问题
    def threeSum(self, nums: List[int]) -> List[List[int]]:
        res = set()
        nums.sort()
        for i in range(len(nums)):
            for j in range(i + 1, len(nums)):
                for k in range(j + 1, len(nums)):
                    if nums[i] + nums[j] + nums[k] == 0:
                        tmp = [nums[i], nums[j], nums[k]]
                        res.add(tuple(tmp))
        return [list(i) for i in res]

# 左右指针(双指针)- with extra space
#  - time: O(n2)
#  - space: O(n)
    def threeSum(self, nums):
        """
        :type nums: List[int]
        :rtype: List[List[int]]
        """
        nums.sort()  # time: O(nlogn), space: O(1)/O(n)
        s = set()
        # time: 0(n * n)
        for i in range(len(nums) - 2):
            l, r = i + 1, len(nums) - 1
            while l < r:
                cur_sum = nums[i] + nums[l] + nums[r]
                if cur_sum == 0:
                    s.add(tuple([nums[i], nums[l], nums[r]]))
                    r -= 1
                    l += 1
                elif cur_sum > 0:
                    r -= 1  # move r to the left, to decrease cur_sum
                else:
                    l += 1  # move l to the right, to increase cur_sum

        res = []
        for triplet in s:
            res.append(list(triplet))
        return res
      
# 左右指针(双指针)- without extra space
#  - time: O(n2)
#  - space: O(1)
    def threeSum(self, nums):
        """
        :type nums: List[int]
        :rtype: List[List[int]]
        """

        nums.sort()  # time: O(nlogn), space: O(1)/O(n)
        res = []
        # time: 0(n * n)
        for i in range(len(nums) - 2):
            if i > 0 and nums[i] == nums[i - 1]:  # to skip duplicates, e.g., [-1, -1, 0, 1]
                continue

            l, r = i + 1, len(nums) - 1
            while l < r:
                cur_sum = nums[i] + nums[l] + nums[r]
                if cur_sum == 0:
                    res.append([nums[i], nums[l], nums[r]])
                    r -= 1
                    l += 1
                    while l < r and nums[l] == nums[l - 1]:  # to skip duplicates, e.g., [-1, 0, 0, 1]
                        l += 1
                elif cur_sum > 0:
                    r -= 1  # move r to the left, to decrease cur_sum
                else:
                    l += 1  # move l to the right, to increase cur_sum
        return res

ref

Ref