Lee's Blog
  • 首页
  • 博客
  • 作品
  • 成长
  • 学习
  • 打榜
  • 练习
  • 关于
登录 / 注册
✦

保持联系

关注我的最新动态

GitHubbilibili

© 2026 Lee's Blog

首页/博客/算法学习/算法踩坑-相向左右指针 | 刷题踩坑连载 03
算法踩坑-相向左右指针 | 刷题踩坑连载 03
算法学习2026年7月25日7 分钟阅读

算法踩坑-相向左右指针 | 刷题踩坑连载 03

算法学习
X微博

算法踩坑-相向左右指针 | 刷题踩坑连载 03

本系列持续更新算法刷题过程中亲手踩过的真实坑点,不照搬标准答案,只记录翻车现场、错误根源和修正思路。

上一篇拆解了双指针的第一大类——同向快慢指针,本篇继续补齐双指针的第二大分支:相向左右指针(对撞指针)。覆盖从基础交换到带过滤的回文判断三道入门题,从语法认知到指针逻辑,从基础框架到进阶过滤,所有亲手踩过的坑全汇总在这里。


一、三道入门题核心速览

相向左右指针的核心逻辑是:两个指针分别从数组/字符串的两端出发,向中间靠拢相遇,根据题目要求收缩搜索空间或完成交换、比较。三道经典入门题对应三个梯度的应用场景:

  1. LeetCode 167 两数之和 II - 输入有序数组:利用有序性,通过两端和与目标值的大小关系收缩指针,是对撞指针的经典入门题
  2. LeetCode 344 反转字符串:两端元素两两交换,最基础的对撞指针框架,用来巩固指针移动规则
  3. LeetCode 125 验证回文串:在基础对撞框架上增加无效字符过滤、忽略大小写的逻辑,属于进阶应用

二、语法认知坑:字符/字符串/数组的API大乱炖

从之前的整型数组题转到字符、字符串题,最容易翻车的不是算法逻辑,而是不同数据类型的API混用。以下全是编译阶段直接报错的低级坑,初学者几乎必踩。

1. 多变量声明重复写类型

错误表现:同一行声明两个同类型变量,重复写类型关键字,比如 int left = 0 , int right = s.length; 错误原因:Java 语法规定,同一行声明多个同类型变量时,类型关键字只需要写一次,用逗号分隔变量名即可。重复写 int 会被编译器识别为语法错误。 修正:int left = 0, right = s.length - 1;

2. char 与 String 类型混淆

错误表现:用小写的 string 声明单个字符的临时变量,比如 string temp; 错误根源:对两个类型的定位完全不清楚:

  • char 是 Java 基本数据类型,只能存单个字符,用单引号包裹,比如 'a'
  • String 是引用类型(类),表示一串字符组成的序列,用双引号包裹,比如 "abc" 反转字符串、字符交换场景,临时变量只需要存单个字符,用 char 类型即可,完全不需要 String。

3. 数组与字符串取值方式完全混用

错误表现:两个方向的混用都踩了:

  • 字符数组 char[] 调用 .charAt[] 取元素,还把方法的圆括号写成了方括号
  • 字符串 String 直接用 s[下标] 的方式访问字符 核心结论:两者取值语法完全不通用:
  • 数组(包括 char[]、int[]):直接用 数组名[下标] 访问元素
  • 字符串 String:必须调用方法 s.charAt(下标),方法用圆括号,返回值是 char 类型

4. 长度的属性与方法搞混

错误表现:字符串取长度写 s.length,漏掉括号 对比记忆:

  • 数组:length 是属性,不带括号,比如 nums.length
  • 字符串:length() 是方法,必须带括号,比如 s.length() 两者规则不同,写反了编译器会直接报找不到符号。

5. 布尔常量大小写错误

错误表现:判断条件里写 == True 错误原因:Java 中布尔值是小写关键字 true / false,大写会被识别成未定义的变量,直接编译失败。


三、指针逻辑坑:对撞指针专属的边界与方向翻车

语法改对之后,第二大翻车点就是指针的初始位置和移动方向,属于思路对但细节错,一运行就越界或死循环。

1. 右指针初始值越界:忘记减 1

错误表现:把右指针初始化为数组/字符串的长度,第一次访问元素就抛出下标越界异常。 触发场景:反转字符串、回文判断、两数之和所有对撞指针题型都会踩。 本质原因:Java 数组和字符串的下标都从 0 开始,最后一个元素的下标永远是「长度 - 1」。直接用长度作为初始值,相当于一上来就指向了数组外面。 修正铁律:所有从末尾开始的指针,初始值一律写 长度 - 1。

2. 右指针移动方向完全写反

错误表现:右指针写 right++,越跑越远,要么死循环要么持续越界。 错误根源:混淆了同向指针和相向指针的移动规则:

  • 同向快慢指针:两个指针都向右移动,都是 ++
  • 相向左右指针:两个指针往中间收缩,左指针右移 left++,右指针左移 right-- 记忆点:对撞指针就是两个指针“面对面走”,方向一定相反。

3. 循环条件边界误用

不同题型的循环终止条件有细微差别,写错不会报错但会影响结果:

  • 交换类(如反转字符串):用 left < right 即可,当两指针相遇时,中间元素不需要和自己交换
  • 求和类(如两数之和II):必须用 left < right,不能写 <=,否则会出现同一个元素被使用两次的情况
  • 回文判断类:left < right 和 left <= right 都能通过,相遇时单个字符不影响回文结果

四、进阶场景坑:回文过滤逻辑的典型翻车

做 LeetCode 125 验证回文串时,在基础对撞框架上增加了无效字符过滤、忽略大小写的逻辑,很容易把指针移动顺序写乱,属于对撞指针的进阶翻车点。

1. 把静态方法当成实例方法调用

错误表现:写 s.charAt(left).isLetterOrDigit() 来判断字符是否有效 错误根源:char 是基本数据类型,不能调用任何方法。判断字符类型、转换大小写,都是 Character 包装类的静态方法,需要把字符作为参数传入。 正确写法:

  • 判断是否为字母/数字:Character.isLetterOrDigit(c)
  • 转为小写:Character.toLowerCase(c)

2. 无效字符过滤的指针移动逻辑混乱

错误表现:在循环末尾统一执行 left++ 和 right--,嵌套的判断分支里又额外移动指针,导致有效字符被跳过、过滤逻辑完全失效。 正确分层逻辑:必须遵循“哪边无效移哪边,都有效再一起移”的原则:

  1. 左指针指向无效字符 → 只移动左指针,进入下一轮循环
  2. 右指针指向无效字符 → 只移动右指针,进入下一轮循环
  3. 两边都是有效字符 → 比较是否相等,不相等直接返回 false;相等则两个指针同时向中间移动

3. 过滤时缺失边界保护

潜在翻车点:如果输入全是空格、符号这类无效字符,指针会一直移动,最终超出边界触发越界。 修正方案:每次移动过滤指针时,都要加上 left < right 的边界约束,保证两指针交叉后立刻停止,不会继续越界移动。


五、相向左右指针通用模板

1. 基础对撞模板(无过滤场景:反转、有序求和)

public void baseTemplate(char[] s) {
    int left = 0, right = s.length - 1;
    while (left < right) {
        // 核心处理逻辑:交换、比较求和等
        // ...
        
        // 固定相向移动
        left++;
        right--;
    }
}

2. 带过滤对撞模板(回文类场景)

public boolean filterTemplate(String s) {
    int left = 0, right = s.length() - 1;
    while (left < right) {
        // 跳过左侧无效字符
        while (left < right && !Character.isLetterOrDigit(s.charAt(left))) {
            left++;
        }
        // 跳过右侧无效字符
        while (left < right && !Character.isLetterOrDigit(s.charAt(right))) {
            right--;
        }
        // 比较有效字符
        if (Character.toLowerCase(s.charAt(left)) != Character.toLowerCase(s.charAt(right))) {
            return false;
        }
        left++;
        right--;
    }
    return true;
}

六、对撞指针通用自检三步法

写完代码按这三步自查,能规避 90% 以上的低级错误:

  1. 语法自检:先分清输入是数组还是字符串,取值方式、长度写法、变量类型是否匹配
  2. 指针自检:右指针初始值有没有减 1?移动方向是不是相向?循环条件是否匹配题型
  3. 逻辑自检:带过滤的场景指针移动是否分层?有没有边界保护?比较规则是否符合题目要求

双指针的两大分支(同向快慢、相向左右)到这里就全部收尾,下一篇会进入滑动窗口算法——本质是同向快慢指针的进阶变体,继续更新本系列的踩坑记录。

← 上一篇算法踩坑-同向快慢指针下一篇 →人智和AI的差别小感

相关文章

  • 算法踩坑-同向快慢指针约 7 分钟
  • 算法踩坑-二分法约 6 分钟

评论

需要登录账号才能发表评论。

  • 加载中…

本页内容

  • 算法踩坑-相向左右指针 | 刷题踩坑连载 03
  • 一、三道入门题核心速览
  • 二、语法认知坑:字符/字符串/数组的API大乱炖
  • 1. 多变量声明重复写类型
  • 2. char 与 String 类型混淆
  • 3. 数组与字符串取值方式完全混用
  • 4. 长度的属性与方法搞混
  • 5. 布尔常量大小写错误
  • 三、指针逻辑坑:对撞指针专属的边界与方向翻车
  • 1. 右指针初始值越界:忘记减 1
  • 2. 右指针移动方向完全写反
  • 3. 循环条件边界误用
  • 四、进阶场景坑:回文过滤逻辑的典型翻车
  • 1. 把静态方法当成实例方法调用
  • 2. 无效字符过滤的指针移动逻辑混乱
  • 3. 过滤时缺失边界保护
  • 五、相向左右指针通用模板
  • 1. 基础对撞模板(无过滤场景:反转、有序求和)
  • 2. 带过滤对撞模板(回文类场景)
  • 六、对撞指针通用自检三步法