【基础算法精讲 01】167. 两数之和 II - 输入有序数组……

11 阅读3分钟

题目167. 两数之和 II - 输入有序数组 解法一:两层for循环,暴力求解。Fail,超时! 时间复杂度:O(n^2) 空间复杂度:O(1)

class Solution:
    def twoSum(self, numbers: List[int], target: int) -> List[int]:
        n = len(numbers)
        for i in range(n - 1):
            for j in range(i + 1, n):
                if numbers[i] + numbers[j] == target:
                    return [i + 1, j + 1]

解法二:双指针。前提:数组是有序数组 时间复杂度:O(n) 空间复杂度:O(1)

# 解法二:
class Solution:
    def twoSum(self, numbers: List[int], target: int) -> List[int]:
        # 数组 已经排好序,两数之和 == target,两个索引不同
        n = len(numbers)
        # 双指针
        left = 0
        right = n - 1
        while left < right: # 因为有唯一解,条件可替换成True
            s = numbers[left] + numbers[right]
            if s < target:
                left += 1
            elif s > target:
                right -= 1
            else:
                return [left + 1, right + 1]
        return []

题目15. 三数之和 解法:数组排序后,for循环嵌套双指针→将三数之和转化为两数之和。注意三个数都要去重、以及小优化 时间复杂度:O(n^2) 空间复杂度:O(1)

class Solution:
    def threeSum(self, nums: List[int]) -> List[List[int]]:
        # 数组,未排序→排序
        # i != j != k, 有序
        # 三数之和为0,且不重复→去重
        nums.sort()
        n = len(nums)
        ans = []
        for i in range(n - 2):
            x = nums[i]
            # 剪枝
            if i > 0 and nums[i] == nums[i - 1]:
                continue
            # 优化一
            if x + nums[-2] + nums[-1] < 0:
                continue
            # 优化二
            if x + nums[i + 1] + nums[i + 2] > 0:
                break
            # 双指针
            left = i + 1
            right = n - 1
            while left < right:
                s = x + nums[left] + nums[right]
                if s < 0:
                    left += 1
                elif s > 0:
                    right -= 1
                else:
                    ans.append([x, nums[left], nums[right]])
                    left += 1
                    right -= 1
                    while left < right and nums[left] == nums[left - 1]: # 去重
                        left += 1
                    while right > left and nums[right] == nums[right + 1]: # 去重
                        right -= 1
        return ans

题目2824. 统计和小于目标的下标对数目 解法:排序后同两数之和,双指针 时间复杂度:O(n) 空间复杂度:O(1)

class Solution:
    def countPairs(self, nums: List[int], target: int) -> int:
        # 排序、计数器
        nums.sort()
        n = len(nums)
        cnt = 0
        # 双指针
        left = 0
        right = n - 1
        while left < right:
            s = nums[left] + nums[right]
            # 优化一
            if nums[0] + nums[1] > target:
                break
            if s >= target:
                right -= 1
            else:
                cnt += right - left
                left += 1
        return cnt

题目16. 最接近的三数之和 解法:三数之和的变形, 时间复杂度:O(n^2) 空间复杂度:O(1)

class Solution:
    def threeSumClosest(self, nums: List[int], target: int) -> int:
        nums.sort()
        n = len(nums)
        ans = inf
        for i in range(n - 2):
            x = nums[i]
            if i > 0 and x == nums[i - 1]:
                continue

            # 优化一
            s = x + nums[i + 1] + nums[i + 2]
            if s > target:
                if s - target < abs(ans - target):
                    ans = s
                return ans

            # 双指针
            left, right = i + 1, n - 1
            while left < right:
                s = x + nums[left] + nums[right]
                if s == target:
                    return target
                if abs(s - target) < abs(ans - target):
                    ans = s
                if s > target:
                    right -= 1
                else:
                    left += 1
        return ans

题目18. 四数之和 解法:两层循环+双指针,去重、两层循环内均可适当优化

class Solution:
    def fourSum(self, nums: List[int], target: int) -> List[List[int]]:
        nums.sort()
        ans = []
        n = len(nums)
        for a in range(n - 3):
            x = nums[a]
            if a > 0 and x == nums[a - 1]:
                continue
            # 优化一
            if x + nums[a + 1] + nums[a + 2] + nums[a + 3] > target:
                break
            # 优化二
            if x + nums[-3] + nums[-2] + nums[-1] < target:
                continue
            
            for b in range(a + 1, n - 2):
                y = nums[b]
                # 优化三
                if b > a + 1 and y == nums[b - 1]:
                    continue
                # 优化四
                if x + y + nums[-2] + nums[-1] < target:
                    continue
                if x + y + nums[b + 1] + nums[b + 2] > target:
                    break
                # 双指针
                c, d = b + 1, n - 1
                while c < d:
                    s = x + y + nums[c] + nums[d]
                    if s == target:
                        ans.append([x, y, nums[c], nums[d]])
                        c += 1
                        d -= 1
                        while c < d and nums[c] == nums[c - 1]:
                            c += 1
                        while d > c and nums[d] == nums[d + 1]:
                            d -= 1
                    elif s > target:
                        d -= 1
                    else: # s < target
                        c += 1
        return ans

时间复杂度:O(n^3) 空间复杂度:O(1)

题目611. 有效三角形的个数 解法-代码实现:两边之和大于第三边,控制第3边,一点点扩大范围、第1/2条边依次移动

class Solution:
    def triangleNumber(self, nums: List[int]) -> int:
        nums.sort()
        # 三角形定理:两边之和大于第三边,控制第3边,一点点扩大范围
        # 计数器
        cnt = 0
        n = len(nums)
        # i,j,k分别代表三边索引,a,b,c分别对应三边的值
        for k in range(2, n):
            c = nums[k]
            i = 0 # a = nums[i]
            j = k - 1 # b = nums[j]
            while i < j:
                if nums[i] + nums[j] > c:
                    cnt += j - i
                    j -= 1
                else:
                    i += 1
        return cnt

时间复杂度:O(n^2) 空间复杂度:O(1)