回文串算法题

回文串是一个正着读和反着读顺序一样的字符串。"aba" 是回文串,"abba" 是回文串,"abc" 不是回文串。

回文串的题目,都要使用一个基本的逻辑,就是判断当前这个字符串是不是回文串。以 c++ 为例,代码如下。这种方法也可以称为双指针法,两个指针从字符串的两端向中间遍历每个字符,如果中间发现两个字符不相同,则不是回文字符串;遍历到最后,说明是回文串。

    bool isPalindrome(const string s) {int len = s.size();if (len <= 1) {return true;}int left = 0;int right = len - 1;while (left < right) {if (s[left] != s[right]) {return false;}left++;right--;}return true;}

双指针法,在其它数据结构题目中也会用到,比如链表中会用到快慢指针,也属于双指针。快速排序算法中,给选中的数据找到合适的位置,也会使用两个指针从两边向中间对数据进行遍历,也属于双指针。

判断回文串,也可以使用从中间向两边的方法,使用这种方法时,首先需要判断字符串的长度是奇数还是偶数,如果是奇数的话,那么两个指针从中间的位置开始向两边遍历;偶数的话,两个指针分别从中间两个元素的位置开始遍历。
没有特殊要求的话,优先选用从两边向中间的方式来判断一个字符串是不是回文串。

1 验证回文串

leetcode:验证回文串

题目要求判断给定的字符串是不是回文串,如果是回文串,则返回 true;如果原字符串不是回文串,那么最多可以删除一个字符,如果删除一个字符之后的字符串是回文串,那么返回 true,否则返回 false。

1.1 基础算法

(1)判断原字符串是不是回文串,是回文串返回 true;否则执行第 2 步

(2)遍历字符串的每个字符,分别将每个字符删除,判断删除字符之后的字符串是不是回文串。

如果是回文串,则返回 true,停止遍历;如果字符遍历结束,则返回 false。

这种算法的时间复杂度是 O(n 的平方),偏大,所以优先选用第二种方法,第二种算法的时间复杂度是 O(n)。

1.2 双指针,动态判断

(1)使用双指针,从两边向中间遍历每个字符

(2)如果遍历到两个字符不相等,则讨论如下两种情况

① 删除左边的字符,判断子串是不是回文串,是的话则返回 true

② 删除右边的字符,判断子串是不是回文串,是的话返回 true

如果两种情况都不是回文串,那么返回 false。

(3)如果字符串遍历结束,都满足回文串的要求,则返回 true

class Solution {
public:bool validPalindrome(string s) {int len = s.size();int left = 0;int right = len - 1;bool result = true;while (left < right) {if (s[left] != s[right]) {if (isPalindrome(s.substr(left + 1, right - left))) {return true;}if (isPalindrome(s.substr(left, right - left))) {return true;}return false;}left++;right--;}return true;}bool isPalindrome(const string s) {int len = s.size();if (len <= 1) {return true;}int left = 0;int right = len - 1;while (left < right) {if (s[left] != s[right]) {return false;}left++;right--;}return true;}
};

2 最长回文子串

leetcode:最长回文子串

一个字符串 s,找到 s 中最长的回文子串。

2.1 动态规划

将所有的子串的情况都遍历到,在遍历的过程中,判断子串是不是回文串,如果是回文串并且长度比已有的回文串长的话,那么就更新结果。属于动态规划算法。

这个算法的事件复杂度是 O(n 的平方),时间复杂度较高,在 leetcode 上运行时会超时。

class Solution {
public:string longestPalindrome(string s) {int size = s.size();for (int i = 0; i < size; i++) {for (int j = i; j < size; j++) {if (isPalindrome(s.substr(i, j - i + 1))) {if (j - i + 1 > max_length) {max_length = j - i + 1;max_str = s.substr(i, j - i + 1);}}}}return max_str;}private:bool isPalindrome(string s) {int size = s.size();int i = 0;int j = size - 1;while (i < j) {if (s[i] != s[j]) {return false;}i++;j--;}return true;}private:int max_length = 0;string max_str;
};

这个题目要找的是最长回文子串,我们能想到 j 的遍历从大向小遍历。这样遍历的话就是先遍历长度大的字符串,再遍历长度小的字符串。当第一个遍历到一个字符串是回文串,那么这个回文串就是长度最大的回文串,就可以直接返回。从小向大进行遍历,当遍历到这个字符串是回文串的时候,仍然不能返回,因为不能确定这个字符串是不是长度最大的回文串,需要将所有情况都遍历完毕才能确定最大的回文字符串。再进一步思考,我们可以以子串的长度作为遍历的依据,长度从大到小进行遍历。

如下是使用 c 语言实现的算法。

char ret[1001] = {'\0'};
char* longestPalindrome(char* s) {int length = strlen(s);if (length <= 1) {return s;}memset(ret, 0, 1001);for (int len = length; len >= 1; len--) {for (int i = 0; i < length; i++) {if (i + len - 1 >= length) {break;}int start_index = i;int end_index = i + len - 1;if (isPalindrome(s, start_index, end_index)) {int index = 0;for (int i = start_index; i <= end_index; i++) {ret[index] = s[i];index++;}return ret;}}}return NULL;
}int isPalindrome(char *s, int start_index, int end_index) {while (start_index < end_index) {if (s[start_index] != s[end_index]) {return 0;}start_index++;end_index--;}return 1;
}

官方题解中也是遍历了子串的长度,但是是从小到大进行遍历的,同时还记录了已经遍历过的子串的结果。当判断长度较大的字符串是不是回文串时,可以直接基于历史记录来做判断。这也是动态规划常用的思路,就是在遍历的过程中记录历史信息,这样在后边的遍历中可以直接使用已经记录的历史信息。

官方题解中,正因为长度是从小到大进行遍历的,所以在遍历的时候判断字符串是不是回文串的时候,可以使用历史信息进行判断。因为 s[i][j] 比 s[i + 1][j - 1] 的长度要大,后者是不是回文串已经是确定的。

2.2 中心扩展法

leetcode 官方题解中提供了另外一种方法,中心扩展法。

这个问题的多种算法之间的区别就是遍历的对象不一样:

(1)两级遍历,遍历字符串的索引

(2)两级遍历,一级遍历子串的长度,一级遍历字符串的索引

(3)中心扩展法也是遍历字符串的索引,不过在计算逻辑上,是把索引当成了要遍历的子串的中心

class Solution {
public:string longestPalindrome(string s) {int size = s.size();int start = 0;int end = 0;for (int i = 0; i < size; i++) {int left1 = i;int right1 = i;int left2 = i;int right2 = i + 1;// 从中心向两边扩展,要考虑两种情况// 奇数的情况,偶数的情况centerExpand(s, left1, right1);centerExpand(s, left2, right2);if (right1 - left1 > end - start) {start = left1;end = right1;}if (right2 - left2 > end - start) {start = left2;end = right2;}}return s.substr(start, end - start + 1);}void centerExpand(string &s, int &left, int &right) {while (left >= 0 && right < s.size() && s[left] == s[right]) {left--;right++;}// 循环退出,说明最后一个索引不满足回文串的情况// 要么是 left 和 right 越界了,要么是当前这两个字符不相等// 这两种情况下,left 需要 ++, right 需要 --left++;right--;}};

3 分割回文子串

leetcode:分割回文子串

本文,用基础的算法去思考的话,很难思考下去,遇到这种情况一般要考是不是可以使用递归算法。

class Solution {
public:vector<vector<string>> partition(string s) {partitionHelper(s, 0);return result_;}void partitionHelper(const string &s, int start_index) {int len = s.size();if (start_index >= len) {result_.push_back(one_instance_);return;}for (int i = start_index; i < len; i++) {if (isPalindome(s, start_index, i)) {one_instance_.push_back(s.substr(start_index, i - start_index + 1));partitionHelper(s, i + 1);one_instance_.pop_back();}}}bool isPalindome(const string &s, int start, int end) {if (start >= end) {return true;}if (flag[start][end] == 1) {return true;}if (flag[start][end] == -1) {return false;}int tmp_start = start;int tmp_end = end;while (tmp_start < tmp_end) {if (s[tmp_start] != s[tmp_end]) {flag[tmp_start][tmp_end] = -1;flag[start][end] = -1;return false;}tmp_start++;tmp_end--;}flag[start][end] = 1;return true;}private:int flag[20][20] = {0};vector<vector<string>> result_;vector<string> one_instance_;
};

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/846212.shtml

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

相关文章

六一去哪儿,跟着蒙自源开启一段关于童年记忆与美味奇妙旅程

夏日微风轻拂&#xff0c;童心随风起舞。在这个充满欢声笑语的季节里&#xff0c;蒙自源诚挚地邀请您和您的家人&#xff0c;一同参加为六一儿童节精心准备的庆祝活动&#xff0c;共同开启一段关于童年记忆与美味的奇妙旅程。 从5月25日起&#xff0c;蒙自源的各大门店将化身为…

【R语言入门】 在Anaconda Navigator平台使用R语言编程

R语言入门 - 在Anaconda Navigator平台使用R语言编程 R Essentials - Using R Programming Language on Anaconda Navigator Platform By JacksonML 02/06/2024 1. 安装Anaconda Navigator 为了持续研究数据科学&#xff0c;笔者一开始就在电脑上安装了Jupyter Notebook&am…

services层和controller层

services层 我的理解&#xff0c;services层是编写逻辑代码语句最多的一个层&#xff0c;非常重要&#xff0c;在实际的项目中&#xff0c;负责调用Dao层中的mybatis&#xff0c;在我的项目中它调用的是这两个文件 举例代码如下 package com.example.sfdeliverysystem.servic…

详解 Spark 核心编程之累加器

累加器是分布式共享只写变量 一、累加器功能 ​ 累加器可以用来把 Executor 端的变量信息聚合到 Driver 端。在 Driver 程序中定义的变量&#xff0c;在 Executor 端的每个 Task 都会得到这个变量的一份新的副本&#xff0c;每个 task 更新这些副本的值后&#xff0c;传回 Dri…

LeetCode 两两交换链表中的节点

原题链接24. 两两交换链表中的节点 - 力扣&#xff08;LeetCode&#xff09; 思路&#xff0c;请看图片的过程模拟&#xff0c;这里添加了一个哨兵节点0&#xff0c;目的是为了方便操作&#xff0c;得到指向1节点的指针。 class Solution {public:ListNode* swapPairs(ListNod…

天润融通:大模型与生成式AI的融合,开辟零售增长新路径

大模型时代&#xff0c;零售消费企业如何用数智化出奇制胜。 近期&#xff0c;由国内领先的科技产业资本研究平台第一新声举办的“2024年中国CIO数字策略大会”在上海隆重举行。 天润融通消费零售行业顾问颜欣欣先生受邀参与此次大会&#xff0c;并发表了《大模型实践分享:基…

基于Nginx和Consul构建自动发现的Docker服务架构——非常之详细

基于Nginx和Consul构建自动发现的Docker服务架构 文章目录 基于Nginx和Consul构建自动发现的Docker服务架构资源列表基础环境一、安装Docker1.1、Consul节点安装1.2、registrator节点安装 二、案例前知识点2.1、什么是Consul 三、基于Nginx和Consul构建自动发现的Docker服务架构…

智慧商砼搅拌车安监运营管理的创新实践

随着城市化进程的加速&#xff0c;商砼搅拌车作为城市建设的重要设备&#xff0c;其安全管理与运营效率直接关系到工程质量和施工进度。近年来&#xff0c;通过引入先进的4G无线视频智能车载终端套件&#xff0c;我们实现了对商砼搅拌车的高精度定位、实时音视频调度、实时油量…

Matlab2010安装注册+激活(保姆级教程)

目录 一、软件安装 二、软件激活 三、软件测试 Matlab2010压缩包: 链接&#xff1a;https://pan.baidu.com/s/1bX4weZ0nC-4zlDLUiSKcRQ?pwdxljj 提取码&#xff1a;xljj 一、软件安装 1.解压所给压缩包&#xff0c;目录双击setup.exe打开. (如果用户名为中文则会遇到这个…

virtualbox虚拟机、centos7安装增强工具

文章目录 1. virtualBox语言设置2. 设置终端启动快捷键3. 添加virtualbox 增强工具4. 设置共享文件夹 1. virtualBox语言设置 virtualbox -> file -> perferences -> language ->选择对应的语言 -> OK virtualbox -> 管理 -> 全局设定 -> 语言 -> …

Ubuntu server 24 (Linux) 普通用户不能sudo 也不能使用root登录 忘记root密码 修复解决方案

一 普通用户无法sudo&#xff0c;同时也没有其他用户可用 #test用户使用sudo报错&#xff0c;没有权限 testtest:~$ sudo vi /etc/sudoers [sudo] password for test: test is not in the sudoers file. 二 关闭ubuntu 服务器&#xff0c;重新开机 按下ESC 键 1 出现GRUB…

SAP跨服务器传输请求号

环境一、两台服务器并没有维护连接传输线路&#xff08;DEV和QAS&#xff09; 环境二、需要将外部公司服务器上的请求号传输到内部服务器中 方式&#xff1a;先从开发环境或服务器中下载请求号&#xff0c;再将请求号上传到目标服务器或环境中&#xff0c;在目标服务器使用ST…

JAVA流程控制do...while循环

1.对于while语句而言&#xff0c;如果不满足条件&#xff0c;则不能进入循环。但有时候我们需要即使不满足条件&#xff0c;也至少执行一次 2.do...while循环和while循环相似&#xff0c;不同的是&#xff0c;do...whlie循环至少会执行一次 do{ //代码语句 }while&#xff08;…

yolov10/v8 loss详解

v10出了就想看看它的loss设计有什么不同&#xff0c;看下来由于v8和v10的loss部分基本一致就放一起了。 v10的论文笔记&#xff0c;还没看的可以看看&#xff0c;初步尝试耗时确实有提升 好记性不如烂笔头&#xff0c;还是得记录一下&#xff0c;以免忘了&#xff0c;废话结束…

【基础算法总结】模拟算法

模拟算法 1.替换所有的问号2.提莫攻击3.Z 字形变换4.外观数列5.数青蛙 点赞&#x1f44d;&#x1f44d;收藏&#x1f31f;&#x1f31f;关注&#x1f496;&#x1f496; 你的支持是对我最大的鼓励&#xff0c;我们一起努力吧!&#x1f603;&#x1f603; 模拟算法 —> 比葫芦…

Python魔法之旅-魔法方法(10)

目录 一、概述 1、定义 2、作用 二、应用场景 1、构造和析构 2、操作符重载 3、字符串和表示 4、容器管理 5、可调用对象 6、上下文管理 7、属性访问和描述符 8、迭代器和生成器 9、数值类型 10、复制和序列化 11、自定义元类行为 12、自定义类行为 13、类型检…

07.与jenkins集成实现cicd

7.与jenkins集成实现ci/cd ip地址服务内存192.168.111.11kube-apiserver 80801G192.168.111.13k8s-node22G192.168.111.14jenkins(tomcat jdk) 8080 kubelet docker1G192.168.111.15gitlab 8080,80 docker2G 通过jenkins一键操作实现发布服务&#xff0c;jenkins对接k8s …

简单的小波自编码器降噪(Python)

代码很简单&#xff0c;很容易读懂。 import kerasfrom keras import layersfrom keras.datasets import mnistimport numpy as npimport matplotlib.pyplot as pltimport pywtimport tensorflow as tfimport torch#加载经典的mnist手写数字图像(x_train, _), (x_test, _) mn…

基于Chisel的FPGA流水灯设计

Chisel流水灯 一、Chisel&#xff08;一&#xff09;什么是Chisel&#xff08;二&#xff09;Chisel能做什么&#xff08;三&#xff09;Chisel的使用&#xff08;四&#xff09;Chisel的优缺点1.优点2.缺点 二、流水灯设计 一、Chisel &#xff08;一&#xff09;什么是Chise…

uniapp 怎么设置凸起的底部tabbar

1. uniapp 怎么设置凸起的底部tabbar 1.1. 方案一系统提供 1.1.1. 使用uniapp官方提供的属性midButton 使用时&#xff0c;list数组须为偶数 &#xff08;1&#xff09;pages.json "tabBar": {"custom": true,"color": "#8F8F94",&q…