洋仔的博客 洋仔的博客
首页
  • 个人心法总结

    • 价值心法
  • 技术文档
  • GitHub技巧
  • Nodejs
  • 博客搭建
  • iOS基础知识
  • 前端
  • 学习
  • 面试
  • 心情杂货
  • 实用技巧
  • 投资体系
  • 毛选
  • 友情链接
关于
收藏
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

洋仔

奋斗的小青年
首页
  • 个人心法总结

    • 价值心法
  • 技术文档
  • GitHub技巧
  • Nodejs
  • 博客搭建
  • iOS基础知识
  • 前端
  • 学习
  • 面试
  • 心情杂货
  • 实用技巧
  • 投资体系
  • 毛选
  • 友情链接
关于
收藏
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • 技术文档

  • GitHub技巧

  • Nodejs

  • 博客搭建

  • iOS基础知识

    • iOS底层相关

    • Runloop系列

    • Runtime系列

    • 内存管理系列

    • Block系列

    • 线程系列

    • KVC跟KVO系列以及通知中心

    • UI系列

    • 离屏渲染系列

    • 组件化系列跟架构

    • OC跟webview交互系列

    • 持久化系列

    • APP编译系列

    • APP性能优化系列

    • cocoapods系列

    • swift系列

    • Git系列

    • 网络相关

    • 三方库系列

    • 系统原理

    • 总结系列

    • 算法系列

    • 数据结构系列

      • 数组系列

        • 数组
        • 数组双指针系列之快慢指针
        • 数组双指针系列之对撞指针
          • 1. 双指针简介
          • 2. 对撞指针
            • 2.1 对撞指针求解步骤
            • 2.2 对撞指针伪代码模板
            • 2.3 对撞指针适用范围
            • 2.5 验证回文串
          • 对撞指针题目
        • 数组双指针系列之分离双指针
        • 数组滑动窗口系列
      • 链表系列

      • 堆栈系列

      • 队列系列

      • 哈希表

      • 字符串系列

      • 树

      • 图

      • 构建知识体系核心思想
  • 前端

  • 技术
  • iOS基础知识
  • 数据结构系列
  • 数组系列
洋仔
2024-10-25
目录

数组双指针系列之对撞指针

# 01. 数组双指针知识

# 1. 双指针简介

双指针(Two Pointers):指的是在遍历元素的过程中,不是使用单个指针进行访问,而是使用两个指针进行访问,从而达到相应的目的。如果两个指针方向相反,则称为「对撞指针」。如果两个指针方向相同,则称为「快慢指针」。如果两个指针分别属于不同的数组 / 链表,则称为「分离双指针」。

在数组的区间问题上,暴力算法的时间复杂度往往是 O(n2)。而双指针利用了区间「单调性」的性质,可以将时间复杂度降到 O(n)。

# 2. 对撞指针

对撞指针:指的是两个指针 left、right 分别指向序列第一个元素和最后一个元素,然后 left 指针不断递增,right 不断递减,直到两个指针的值相撞(即 left==right),或者满足其他要求的特殊条件为止。

对撞指针

# 2.1 对撞指针求解步骤

  1. 使用两个指针 left,right。left 指向序列第一个元素,即:left=0,right 指向序列最后一个元素,即:right=len(nums)−1。
  2. 在循环体中将左右指针相向移动,当满足一定条件时,将左指针右移,left+=1。当满足另外一定条件时,将右指针左移,right−=1。
  3. 直到两指针相撞(即 left==right),或者满足其他要求的特殊条件时,跳出循环体。

# 2.2 对撞指针伪代码模板

left, right = 0, len(nums) - 1

while left < right:
    if 满足要求的特殊条件:
        return 符合条件的值 
    elif 一定条件 1:
        left += 1
    elif 一定条件 2:
        right -= 1

return 没找到 或 找到对应值
1
2
3
4
5
6
7
8
9
10
11

# 2.3 对撞指针适用范围

对撞指针一般用来解决有序数组或者字符串问题:

  • 查找有序数组中满足某些约束条件的一组元素问题:比如二分查找、数字之和等问题。
  • 字符串反转问题:反转字符串、回文数、颠倒二进制等问题。

下面我们根据具体例子来讲解如何使用对撞指针来解决问题。

# 2.4.2 题目大意

描述:给定一个下标从 1 开始计数、升序排列的整数数组:numbers 和一个目标值 target。

要求:从数组中找出满足相加之和等于 target 的两个数,并返回两个数在数组中下的标值。

示例:

  • 示例 1:
输入:numbers = [2,7,11,15], target = 9
输出:[1,2]
解释:2 与 7 之和等于目标数 9 。因此 index1 = 1, index2 = 2 。返回 [1, 2] 。
1
2
3

# 2.4.3 解题思路

这道题如果暴力遍历数组,从中找到相加之和等于 target 的两个数,时间复杂度为 O(n2),可以尝试一下。

class Solution:
    def twoSum(self, numbers: List[int], target: int) -> List[int]:
        size = len(numbers)
        for i in range(size):
            for j in range(i + 1, size):
                if numbers[i] + numbers[j] == target:
                    return [i + 1, j + 1]
        return [-1, -1]
1
2
3
4
5
6
7
8

结果不出意外的超时了。所以我们要想办法减少时间复杂度。

# 思路 1:对撞指针 (opens new window)

可以考虑使用对撞指针来减少时间复杂度。具体做法如下:

  1. 使用两个指针 left,right。left 指向数组第一个值最小的元素位置,right 指向数组值最大元素位置。
  2. 判断两个位置上的元素的和与目标值的关系。
    1. 如果元素和等于目标值,则返回两个元素位置。
    2. 如果元素和大于目标值,则让 right 左移,继续检测。
    3. 如果元素和小于目标值,则让 left 右移,继续检测。
  3. 直到 left 和 right 移动到相同位置停止检测。
  4. 如果最终仍没找到,则返回 [−1,−1]。
# 思路 1:代码
class Solution:
    def twoSum(self, numbers: List[int], target: int) -> List[int]:
        left = 0
        right = len(numbers) - 1
        while left < right:
            total = numbers[left] + numbers[right]
            if total == target:
                return [left + 1, right + 1]
            elif total < target:
                left += 1
            else:
                right -= 1
        return [-1, -1]
1
2
3
4
5
6
7
8
9
10
11
12
13
# 思路 1:复杂度分析
  • 时间复杂度:O(n)。
  • 空间复杂度:O(1)。只用到了常数空间存放若干变量。

# 2.5 验证回文串

# 2.5.1 题目链接

  • 125. 验证回文串 - 力扣(LeetCode) (opens new window)

# 2.5.2 题目大意

描述:给定一个字符串 s。

要求:判断是否为回文串(只考虑字符串中的字母和数字字符,并且忽略字母的大小写)。

说明:

  • 回文串:正着读和反着读都一样的字符串。
  • 1≤s.length≤2∗105。
  • s 仅由可打印的 ASCII 字符组成。

示例:

输入: "A man, a plan, a canal: Panama"
输出:true
解释:"amanaplanacanalpanama" 是回文串。


输入:"race a car"
输出:false
解释:"raceacar" 不是回文串。
1
2
3
4
5
6
7
8

# 2.5.3 解题思路

# 思路 1:对撞指针
  1. 使用两个指针 left,right。left 指向字符串开始位置,right 指向字符串结束位置。
  2. 判断两个指针对应字符是否是字母或数字。 通过 left 右移、right 左移的方式过滤掉字母和数字以外的字符。
  3. 然后判断 s[start] 是否和 s[end] 相等(注意大小写)。
    1. 如果相等,则将 left 右移、right 左移,继续进行下一次过滤和判断。
    2. 如果不相等,则说明不是回文串,直接返回 False。
  4. 如果遇到 left==right,跳出循环,则说明该字符串是回文串,返回 True
# 思路 1:代码 (opens new window)
class Solution:
    def isPalindrome(self, s: str) -> bool:
        left = 0
        right = len(s) - 1

        while left < right:
            if not s[left].isalnum():
                left += 1
                continue
            if not s[right].isalnum():
                right -= 1
                continue

            if s[left].lower() == s[right].lower():
                left += 1
                right -= 1
            else:
                return False
        return True
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 思路 1:复杂度分析
  • 时间复杂度:O(len(s))。
  • 空间复杂度:O(len(s))。

# 对撞指针题目 (opens new window)

题号 标题 题解 标签 难度
0167 两数之和 II - 输入有序数组 (opens new window) Python (opens new window) 数组、双指针、二分查找 中等
0344 反转字符串 (opens new window) Python (opens new window) 双指针、字符串 简单
0345 反转字符串中的元音字母 (opens new window) Python (opens new window) 双指针、字符串 简单
0125 验证回文串 (opens new window) Python (opens new window) 双指针、字符串 简单
0011 盛最多水的容器 (opens new window) Python (opens new window) 贪心、数组、双指针 中等
0611 有效三角形的个数 (opens new window) Python (opens new window) 贪心、数组、双指针、二分查找、排序 中等
0015 三数之和 (opens new window) Python (opens new window) 数组、双指针、排序 中等
0016 最接近的三数之和 (opens new window) Python (opens new window) 数组、双指针、排序 中等
0018 四数之和 (opens new window) Python (opens new window) 数组、双指针、排序 中等
0259 较小的三数之和 (opens new window) Python (opens new window) 数组、双指针、二分查找、排序 中等
0658 找到 K 个最接近的元素 (opens new window) Python (opens new window) 数组、双指针、二分查找、排序、滑动窗口、堆(优先队列) 中等
1099 小于 K 的两数之和 (opens new window) Python (opens new window) 数组、双指针、二分查找、排序 简单
0075 颜色分类 (opens new window) Python (opens new window) 数组、双指针、排序 中等
0360 有序转化数组 (opens new window) Python (opens new window) 数组、数学、双指针、排序 中等
0977 有序数组的平方 (opens new window) Python (opens new window) 数组、双指针、排序 简单
0881 救生艇 (opens new window) Python (opens new window) 贪心、数组、双指针、排序 中等
0042 接雨水 (opens new window) Python (opens new window) 栈、数组、双指针、动态规划、单调栈 困难
0443 压缩字符串 (opens new window) Python (opens new window) 双指针、字符串 中等
编辑 (opens new window)
数组双指针系列之快慢指针
数组双指针系列之分离双指针

← 数组双指针系列之快慢指针 数组双指针系列之分离双指针→

最近更新
01
数组
10-25
02
数组双指针系列之快慢指针
10-25
03
数组双指针系列之分离双指针
10-25
更多文章>
Theme by Vdoing | Copyright © 2019-2024 Evan Xu | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式