相向双指针

原创@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        

<think>好的,用户想了解如何在编程中实现和使用双指针算法。首先,我需要回忆双指针算法的基本概念和应用场景。根据提供的引用内容,双指针通常分为快慢指针和左右指针,或者相向双指针,用于数组和链表的处理。用户可能需要具体的实现步骤和例子。 首先,我应该明确双指针的分类,比如快慢指针用于链表问题,比如检测循环;而相向指针可能用于数组中的两数之和等问题。然后,我需要结合引用中的例子,比如引用[4]提到的相向双指针用于查找和或差等于目标值的情况。 接下来,我需要考虑如何结构化回答。可能需要分步骤说明,比如确定问题类型、初始化指针、移动规则等。同时,要提供代码示例,比如Python实现的两数之和、链表去重等。另外,用户可能需要知道优化方法或注意事项,比如指针移动的条件,如何避免重复计算等。 还要注意引用文献的标注,比如在提到双指针的核心思想时引用[^1],在时间复杂度时引用[^2],在相向双指针的应用时引用[^4]。同时,确保所有数学公式使用正确的LaTeX格式,如变量用$x$,独立公式用$$...$$。 可能还需要生成相关问题,比如双指针的变种、优化技巧、错误处理等。需要确保问题相关且有深度,帮助用户进一步学习。 最后,检查回答是否符合系统级指令:使用中文,正确格式的LaTeX,引用标注正确,结构清晰,分步骤说明,代码示例正确,相关问题合理。</think>### 双指针算法实现与使用方法 #### 一、双指针算法核心思想 双指针算法通过**两个指针(索引或引用)的协同移动**解决特定问题,主要分为两种类型: 1. **同向双指针**(快慢指针):常用于链表遍历、去重等场景,例如删除排序数组中的重复项 2. **相向双指针**(左右指针):适用于有序数组的搜索问题,如两数之和、回文判断[^4] #### 二、实现步骤(以有序数组两数之和为例) 1. **确定指针初始位置** ```python left = 0 right = len(nums) - 1 ``` 2. **设定终止条件** ```python while left < right: ``` 3. **定义指针移动规则** $$ \text{若 } nums[left] + nums[right] > target \Rightarrow right -= 1 $$ $$ \text{若 } nums[left] + nums[right] < target \Rightarrow left += 1 $$ 4. **完整代码示例** ```python def two_sum(nums, target): left, right = 0, len(nums)-1 while left < right: current_sum = nums[left] + nums[right] if current_sum == target: return [left+1, right+1] # 返回基于1的索引 elif current_sum < target: left += 1 else: right -= 1 return [] ``` #### 三、典型应用场景 | 场景类型 | 问题示例 | 时间复杂度优化 | |-------------------|----------------------------|----------------------| | 有序数组查找 | 两数之和、三数之和 | $O(n) \rightarrow O(n)$ | | 链表操作 | 环形检测、相交判断 | $O(n^2) \rightarrow O(n)$ | | 滑动窗口 | 最长无重复子串 | $O(n^3) \rightarrow O(n)$ | | 数组去重/元素操作 | 移除重复项、移除指定元素 | $O(n^2) \rightarrow O(n)$ | #### 四、关键优化技巧 1. **指针移动条件**:需根据具体问题建立数学关系式,例如对于三数之和问题: $$ nums[i] + nums[left] + nums[right] = 0 $$ 2. **跳过重复元素**:在移动指针时添加循环判断,避免重复解 3. **边界处理**:特别注意指针越界和循环终止条件 #### 五、错误排查要点 1. 指针移动方向是否正确(左增/右减) 2. 是否遗漏了相等时的处理 3. 循环终止条件是否覆盖所有情况 4. 指针移动后是否需要回溯
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值