Leetcode 验证回文串

news2024/12/25 9:10:58

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

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会判断是否是字母或数字,不是的话返回false
            while(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.coloradmin.cn/o/2140871.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Python画笔案例-051 绘制赵爽弦图

1、绘制赵爽弦图 通过 python 的turtle 库绘制 赵爽弦图&#xff0c;如下图&#xff1a; 2、实现代码 绘制 赵爽弦图&#xff0c;以下为实现代码&#xff1a; """赵爽弦图.py本程序演录了如何自定义形状&#xff0c;如何把它添加到造型字典。赵爽弦图是用来证明…

JAVA算法数据结构第一节稀疏矩阵

一、稀疏矩阵介绍&#xff1a; 稀疏矩阵是一种特殊类型的矩阵&#xff0c;其中大部分元素都是零。在处理这类矩阵时&#xff0c;如果仍然使用标准的矩阵存储方式&#xff08;即传统的二维数组&#xff09;&#xff0c;则会浪费大量的存储空间来保存零值。为了提高存储效率以及…

9.12 TFTP通信

客户端设计&#xff08;仅供参考&#xff09;&#xff1a; 下载本质&#xff1a;读取服务器发送的数据包&#xff0c;写入到本地文件 上传本质&#xff1a;读取本地文件内容&#xff0c;发送给服务器。 1、建立菜单选项&#xff0c;上传和下载。 2、上传功能函数&#xff1a; …

实用类工具!分享6款AI论文一键生成器免费8000字

在当前的学术研究和写作领域&#xff0c;AI论文生成工具的出现极大地提高了写作效率和质量。这些工具不仅能够帮助研究人员快速生成论文草稿&#xff0c;还能进行内容优化、查重和排版等操作。千笔-AIPassPaper是一款备受推荐的AI论文一键生成器。 千笔-AIPassPaper是一个一站式…

centos更改静态ip

点击网络和internet设置 点击更改适配器 、点击属性

15.8 在k8s部署prometheus statefulset

本节重点介绍 : 检查&#xff0c;kube-system ns [rootprome-master01 prometheus]# kubectl get pod -n kube-system NAME READY STATUS RESTARTS AGE coredns-7d75679df-7f7tx 1/1 Running 0 88m coredns-7d75679df-qmzbg 1/1 Running 0 88m etcd-prome-master01 1/1 Runni…

实习期间git的分枝管理以及最常用的命令

各位找工作实习的友友在工作之前一定要把git的相关知识掌握呀&#xff0c;我实现期间被leader说过关于git规范的相关问题了 目前已更新系列&#xff1a; 当前&#xff1a;:实习期间git的分枝管理以及最常用的命令 Redis高级-----持久化AOF、RDB原理 Redis高级---面试总结5种…

[网络]http请求中的URL,方法,header 和 http响应中的状态码

文章目录 一. http请求1. 认识URLurlencode 2. 认识方法应用场景构造http请求 2. 认识请求报头header 二. http响应1. 状态码 一. http请求 1. 认识URL 我们所说的"网址", 其实就是URL(Uniform Resource Locator 统⼀资源定位符) 1.协议方案名 常见的有http和http…

微信小程序----日期时间选择器(自定义时间精确到分秒)

目录 页面效果 代码实现 注意事项 页面效果 代码实现 js Component({/*** 组件的属性列表*/properties: {pickerShow: {type: Boolean,},config: Object,},/*** 组件的初始数据*/data: {pickerReady: false,// pickerShow:true// limitStartTime: new Date().getTime()-…

Acrobat 9 安装教程

软件介绍 Adobe Acrobat 是由Adobe公司开发的一款PDF&#xff08;Portable Document Format&#xff0c;便携式文档格式&#xff09;编辑软件。借助它&#xff0c;可以以PDF格式制作和保存文档&#xff0c;以便于浏览和打印&#xff0c;同时还可以使用一些高级工具来创建、编辑…

MySQL高可用配置及故障切换

目录 引言 一、MHA简介 1.1 什么是MHA&#xff08;MasterHigh Availability&#xff09; 1.2 MHA的组成 1.3 MHA的特点 1.4 MHA工作原理 二、搭建MySQL MHA 2.1 实验思路 2.2 实验环境 1、关闭防火墙和安全增强系统 2、修改三台服务器节点的主机名 2.3 实验搭建 1、…

庆祝中华人民共和国成立75周年答题活

为庆祝中华人民共和国成立75周年&#xff0c;弘扬爱国主义精神&#xff0c;激发广大党员干部和人民群众奋进新征程、建功新时代&#xff0c;奋力推进中国式现代化建设的爱国热情&#xff0c;“学习强国”学习平台采用“线上答题线下竞赛”的形式&#xff0c;举办“学习强国 强国…

数据结构、STL

排序 直接插入排序、希尔排序、选择排序、堆排序、冒泡排序、快速排序、归并排序、基数排序、外部排序 算法稳定性&#xff1a;稳定的&#xff1a;关键字相同的元素在排序后相对位置不变 不稳定&#xff1a;相对位置变化了就是不稳定 排序算法&#xff1a;内部排序和外部排序 …

OrionX vGPU 研发测试场景下最佳实践之CodeServer模式

在之前的文章中&#xff0c;我们讲述了OrionX vGPU基于SSH模式、以及Jupyter模式下的最佳实践&#xff08;文末附回顾链接~&#xff09;&#xff0c;今天&#xff0c;让我们走进CodeServer模式的最佳实践。 • CodeServer模式&#xff1a;微软的VSCode的服务器版本&#xff0c;…

匿名管道详解

进程间通讯的目的 数据传输&#xff1a;一个进程需要把它的数据发送给另一个数据资源共享&#xff1a;多个进程需要共享同样的资源通知事件&#xff1a;一个进程需要向另一个或者一组进程发送消息&#xff0c;通知它发生了某种事件&#xff08;如进程终止时要通知父进程&#…

Python数据分析-Steam 收入排名前 1500 的游戏

一、研究背景 随着全球数字化进程的加速&#xff0c;电子游戏产业已成为全球娱乐产业的重要组成部分&#xff0c;吸引了越来越多的资本与消费者关注。特别是基于互联网的游戏平台&#xff0c;如Steam&#xff0c;已成为全球范围内发行和销售游戏的重要渠道。Steam平台不仅为玩…

高通Liunx 系统镜像编译

本文将会介绍如何在编译高通Liunx代码, 具体可以在高通 Linux | 高通下查看相关信息。 编译服务器配置 首先&#xff0c;准备一台Ubuntu 22.04版本主机或者服务器 1&#xff0c;编译Yocto 系统&#xff0c;需要如下一些配置 sudo apt update sudo apt install repo gawk wg…

钢轨缺陷检测-目标检测数据集(包括VOC格式、YOLO格式)

钢轨缺陷检测-目标检测数据集&#xff08;包括VOC格式、YOLO格式&#xff09; 数据集&#xff1a; 链接&#xff1a;https://pan.baidu.com/s/1h7Dc0MiiRgtd7524cBUOFQ?pwdfr9y 提取码&#xff1a;fr9y 数据集信息介绍&#xff1a; 共有 1493 张图像和一一对应的标注文件 标…

STM32—I2C

1.I2C I2C总线(Inter l0 BUs)是由Philips公司开发的一种通用数据总线两根通信线:SCL(Serial Clock)、SDA(Serial Data)同步&#xff0c;半双工带数据应答支持总线挂载多设备(一主多从、多主多从) MPU6050模块&#xff1a;可以进行姿态测量&#xff0c;使用了12C通信协议 第3个…

IAPP发布《2024年人工智能治理实践报告》

文章目录 前言一、黑箱问题►透明度、可理解性与可解释性二、法律和政策中的注意事项►欧盟的《通用数据保护条例》►欧盟的AI法案►NIST的AI风险管理框架►美国的第14110号行政命令►《生成式人工智能服务管理暂行办法》►新加坡的AI验证三、实施人工智能治理►模型卡与系统卡…