相向双指针

原创@b站灵茶山艾府

有序数组,左指针l,右指针r

力扣167 两数之和II-输入有序数组

题目描述:给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target  的那 两个 整数,并返回它们的数组下标。

class Solution:
    def twoSum(self, numbers: List[int], target: int) -> List[int]:

        l, r = 0, len(numbers) - 1
        while numbers[l] + numbers[r] != target:
            if numbers[l] + numbers[r] > target:
                r -= 1
            else:
                l += 1

        return [l + 1, r + 1]

力扣15 三数之和

题目描述:给你一个整数数组 nums ,判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i != ji != k 且 j != k ,同时还满足 nums[i] + nums[j] + nums[k] == 0 。请你返回所有和为 0 且不重复的三元组。

class Solution:
    def threeSum(self, nums: List[int]) -> List[List[int]]:
        # 解析题目:给出一个数组,返回一个含有多个三元组的数组
        # 如何利用上次的相向双指针的思想?
        # 这道题是否存在暴力解法,如何在暴力解法上进行优化?

        # 三元组的顺序不重要,所以可以先进行排序
        # i < j < k
        # 设定nums[i],寻找另外两个数相加等于-nums[i]
        # 不可以包含重复的三元组

        nums.sort()
        ans = []
        n = len(nums)
        for i in range(n - 2):
            # 为啥那么这里i要>0,哦哦哦不大于零一开始就会报错
            # 这里用continue而不是用while循环让i往后走,因为下次进入for循环i还是会按照顺序来
            if i > 0 and nums[i] == nums[i - 1]:
                continue

            # 细节优化
            # 我的问题是,这个思想能不能直接在下面的循环里体现出来呢
            # break是跳出当前循环直接终止,continue是跳过这一次进入下一次
            if nums[i] + nums[i + 1] + nums[i + 2] > 0:
                break
            if nums[i] + nums[n - 1] + nums[n - 2] < 0:
                continue
            j = i + 1
            k = n - 1
            while j < k:
                s = nums[i] + nums[j] + nums[k]
                if s < 0:
                    j += 1
                elif s > 0:
                    k -= 1
                else:
                    ans.append([nums[i], nums[j], nums[k]])
                    # 这里注意是和前一个值比较,而不是和他的后一个值比较
                    j += 1
                    while j < k and nums[j] == nums[j - 1] :
                        j += 1
                    k -= 1
                    while j < k and nums[k] == nums[k + 1]:
                        k -= 1

        return ans

力扣11 盛最多水的容器

题目描述:

给定一个长度为 n 的整数数组 height 。有 n 条垂线,第 i 条线的两个端点是 (i, 0) 和 (i, height[i]) 。

找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。

返回容器可以储存的最大水量。

class Solution:
    def maxArea(self, height: List[int]) -> int:
        # 时间复杂度O(n) 空间复杂度O(1)
        # 问题的关键在于理清逻辑,对于一个矮一些的边,只要更接近就会变小,在变近的过程中,只有更高的边才有可能出现更大的值,所以可以直接舍弃当前值
        ans = 0 
        left = 0 
        right = len(height) - 1
        while left < right:
            area = (right - left) * min(height[right], height[left])
            ans = max(ans, area)
            if height[right] > height[left]:
                left += 1
            else:
                right -= 1
        return ans

力扣42 接雨水

题目描述:给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。

class Solution:
    def trap(self, height: List[int]) -> int:
        # 方法一:前后缀分解,维护两个数组,分别存储前缀后缀最大值
        # 时间复杂度O(n)空间复杂度O(n)
        # n = len(height)
        # ans = 0
        # pre_max = [0] * n
        # pre_max[0] = height[0]
        # for i in range(1, n):
        #     pre_max[i] = max(height[i], pre_max[i - 1])

        # suf_max = [0] * n
        # suf_max[n - 1] = height[n - 1]
        # for i in range(n - 2, -1, -1): # 从n-2倒序枚举到0
        #     suf_max[i] = max(height[i], suf_max[i + 1])

        # for h, pre, suf in zip(height, pre_max, suf_max):
        #     ans += min(pre, suf) - h

        # return ans

        # 方法二:相向双指针法
        # 时间复杂度O(n) 空间复杂度O(1)
        n = len(height)
        left = 0
        right = n - 1
        pre_max = 0
        suf_max = 0
        ans = 0
        while left <= right:
            pre_max = max(height[left], pre_max)
            suf_max = max(height[right], suf_max)
            if pre_max > suf_max:
                ans += suf_max - height[right]
                right -= 1
            else:
                ans += pre_max - height[left]
                left += 1
        return ans        

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值