当前位置: 首页 > news >正文

Leetcode 验证回文串

在这里插入图片描述
使用双指针技术,逐步比较字符串中的字符,并忽略非字母数字字符以及大小写,判断该字符串是否为回文。以下是详细解释:

1. 核心思想

  • 回文串是指正读和反读都相同的字符串。我们需要从字符串的两端开始比较字符,跳过非字母数字字符,并忽略大小写,直到双指针相遇或者交错。
  • 比如字符串 "A man, a plan, a canal: Panama",当忽略空格、标点符号,且不区分大小写时,实际上是回文。

2. 算法步骤

2.1 初始化双指针
int left = 0, right = s.length() - 1;
  • left 指针指向字符串的第一个字符。
  • right 指针指向字符串的最后一个字符。
2.2 循环比较
while (left < right) {
  • 这个循环是双指针的核心部分。它会一直执行,直到 left 指针和 right 指针交错或相遇。每次循环中,我们逐步比较左右两边的字符。
2.3 跳过非字母数字字符
while (left < right && !isalnum(s[left])) {left++;
}
while (left < right && !isalnum(s[right])) {right--;
}
  • isalnum 是 C++ 的标准函数,作用是判断字符是否为字母或数字。如果 s[left]s[right] 不是字母或数字,我们会将 left 右移或 right 左移,直到找到有效字符。
2.4 忽略大小写比较字符
if (tolower(s[left]) != tolower(s[right])) {return false;
}
  • tolower 是 C++ 的标准函数,用于将字符转换为小写字母。我们使用它来忽略大小写的影响。
  • 如果左右指针指向的字符不相等,我们就可以判断字符串不是回文,直接返回 false
2.5 移动指针
left++;
right--;
  • 如果左右指针的字符相等,我们就继续向内移动 leftright,分别向中间推进,直到它们相遇或者交错。
2.6 循环结束
  • left >= right 时,循环结束。如果在此之前没有返回 false,说明所有字符匹配,字符串是回文。
2.7 返回结果
return true;
  • 如果所有字符匹配,函数最后返回 true,表示字符串是回文。

3. 算法时间复杂度

  • 该算法的时间复杂度是 O(n),其中 n 是字符串的长度。
    • 因为我们使用了双指针技术,每次循环中最多移动 leftright,从而保证每个字符最多被访问一次。
    • 由于要遍历整个字符串,这导致时间复杂度是线性的。

4. 示例分析

示例 1: "A man, a plan, a canal: Panama"
  • 忽略大小写和非字母数字字符后,字符串变为 "amanaplanacanalpanama"
  • 正读和反读相同,所以该字符串是回文,函数返回 true
示例 2: "race a car"
  • 忽略大小写和非字母数字字符后,字符串变为 "raceacar"
  • 正读是 "raceacar",反读是 "racacear",不相同,所以该字符串不是回文,函数返回 false
示例 3: ""(空字符串)
  • 空字符串被认为是回文,因为它正读和反读都是空的,因此返回 true
class Solution {
public:bool isPalindrome(string s) {int left = 0;int right = s.size() - 1;while(left < right) {//先分别把左右指针都移动到字母或数字字符上, isalnum会判断是否是字母或数字,不是的话返回falsewhile(left < right && !isalnum(s[left])) {left++;}while(left < right && !isalnum(s[right])) {right--;}//此时左右指针指向的都是字母或数字字符,然后进行比较if(tolower(s[left]) != tolower(s[right])) {return false;}//此时说明当前两个字符是相等的,那么分别移动左右指针。left++;right--;}return true;}
};

为什么这一部分代码片段中,这两个while循环仍然需要判断left<right?外面的while循环不是已经判断了吗?

        // 找到左边第一个字母或数字字符while (left < right && !isalnum(s[left])) {left++;}// 找到右边第一个字母或数字字符while (left < right && !isalnum(s[right])) {right--;}```这是一个非常好的问题!下面解释为什么在这两个 `while` 循环中仍然需要判断 `left < right`,即使外层已经有了 `while (left < right)` 的判断。### 原因:
在外层的 `while` 循环中,我们逐步推进左右指针来判断字符是否匹配。而在内部的两个 `while` 循环中,我们跳过非字母数字字符(如标点符号、空格等),找到第一个有效的字符来进行比较。然而,由于内部的 `while` 循环是在跳过无效字符的过程中操作的,可能会导致左右指针超越彼此,从而需要再次检查 `left < right` 的条件。#### 举个例子来说明:
考虑一种特殊情况,假设字符串中有大量非字母数字字符,比如:```cpp
s = "!!!!!!!"

在这个例子中,字符串的所有字符都不是字母或数字,所以我们希望通过内部的 while 循环将 leftright 快速移动,直到超越彼此。但是,如果不加 left < right 的判断,可能会发生如下情况:

  1. leftright 都从两端开始,同时跳过无效字符。
  2. left 可能会超过 right
  3. 此时,如果不再检查 left < right,指针会继续移动,导致程序出现逻辑错误,甚至可能访问到数组的非法区域(即超出字符串范围的索引)。

为了防止这种情况的发生,必须在内部的 while 循环中加上 left < right 的检查,以确保即使在跳过无效字符的过程中,左右指针也不会超越对方。

代码片段解析:

// 找到左边第一个字母或数字字符
while (left < right && !isalnum(s[left])) {left++;
}
  • 这个 while 循环是为了从左边跳过所有非字母数字字符,直到找到一个有效的字符。
  • 但如果所有字符都是无效字符(如空格、标点符号等),那么 left 可能会一直增加,直到超过 right
  • 因此,我们在每次移动 left 时,都需要再次检查 left < right,以确保指针不越界。

同理,对于右边的 while 循环:

// 找到右边第一个字母或数字字符
while (left < right && !isalnum(s[right])) {right--;
}
  • 我们需要右指针 right 从右向左移动,跳过所有非字母数字字符。
  • 同样,如果没有有效字符存在,right 可能会不断减少,最终低于 left
  • 需要确保在跳过字符时,right 不会越过 left,因此需要检查 left < right

总结:

尽管外层的 while (left < right) 控制了总体循环,但内部的 while 循环在跳过无效字符时,左右指针可能会过多地移动,因此需要在内部的循环中再次检查 left < right,以防止指针越界或交错的情况发生。这是确保算法正确性和防止潜在错误的关键步骤。


http://www.mrgr.cn/news/27576.html

相关文章:

  • 《硬件架构的艺术》笔记(二):时钟与复位
  • WPF下播放Rtmp的解决方案
  • 【含开题报告+文档+PPT+源码】基于Spring Boot智能综合交通出行管理平台的设计与实现
  • TI毫米波雷达(五)—— chirp
  • 使用pdfjs加载多页pdf并实现打印
  • 《TCP/IP网络编程》学习笔记 | Chapter 10:多进程服务器端
  • AUTOSAR_EXP_ARAComAPI的5章笔记(6)
  • 【网络安全 | Java代码审计】JreCms代码审计
  • 【网络通信基础与实践第三讲】传输层协议概述包括UDP协议和TCP协议
  • PCIe进阶之TL:First/Last DW Byte Enables Rules Traffic Class Field
  • 玩转springboot之为什么springboot可以直接执行
  • MySQl篇(基本介绍)(持续更新迭代)
  • 扣子智能体实战-汽车客服对话机器人(核心知识:知识库和卡片)
  • 01.AI推出Yi模型家族:多维度能力的展示
  • 二叉树算法
  • 召回01 基于物品是协同过滤 ItemCF
  • 【RabbitMQ 项目】服务端:数据管理模块之绑定管理
  • Qwen2-VL的微调及量化
  • L298N电机驱动方案简介
  • Promise查漏及回调地狱结构优化
  • 循环练习 案例
  • Linux权限
  • 鲸天科技外卖会员卡系统更专业
  • XShell快速连接虚拟机(Ubuntu系统)
  • react项目中使用html5-qrcode
  • 《SpringBoot+Vue》Chapter01_SpringBoot介绍