LeetCode - 回文类问题总结

2023-11-04

  • 子串与子序列
    (1)字符子串:指的是字符串中连续的n个字符,如abcdefg中,ab,cde,fg等都属于它的字串。
    (2)字符子序列:指的是字符串中不一定连续但先后顺序一致的n个字符,即可以去掉字符串中的部分字符,但不可改变其前后顺序。如abcdefg中,acdg,bdf属于它的子序列,而bac,dbfg则不是,因为它们与字符串的字符顺序不一致。
      (3) 公共子序列:如果序列C既是序列A的子序列,同时也是序列B的子序列,则称它为序列A和序列B的公共子序列。如对序列 1,3,5,4,2,6,8,7和序列 1,4,8,6,7,5 来说,序列1,8,7是它们的一个公共子序列。最长公共子序列(LCS):就是A和B的公共子序列中长度最长的(包含元素最多的),最长公共子序列(LCS)也不一定唯一,但是长度一定。

一. 最长回文子串: 给定一个字符串 s,找到 s 中最长的回文子串。你可以假设 s 的最大长度为 1000。
示例 :
输入: “babad”
输出: “bab”
注意: “aba” 也是一个有效答案。

class Solution {
public:
	string longestPalindrome(string s) {
		int length = s.size();
		if (length == 0){
			return s;
		}
		int maxCount = 0;
		int left = 0;
		int right = 0;
		vector<vector<bool>> dp(length, vector<bool>(length,false));
		for (int i = 0; i < length; i++)
		{
			for (int j = i; j >= 0; j--){
				dp[i][j] = (s[i] == s[j]) && ((i - j < 3) || dp[i-1][j+1]);
				if (dp[i][j] && (i - j + 1>maxCount))
				{
					maxCount = i - j + 1;
					left = j;
					right = i;
				}
			}
		}
		return s.substr(left, right-left+1);
	}
};

二. 回文子串: 给定一个字符串,你的任务是计算这个字符串中有多少个回文子串。具有不同开始位置或结束位置的子串,即使是由相同的字符组成,也会被计为是不同的子串。
示例 :
输入: “abc”
输出: 3
解释: 三个回文子串: “a”, “b”, “c”.

class Solution {
public:
    int countSubstrings(string s) {
        int length = s.size();
		if (length == 0){
			return 0;
		}
		int count = 0;
	
		vector<vector<bool>> dp(length, vector<bool>(length,false));
		for (int i = 0; i < length; i++)
		{
            count++;
			for (int j = i-1; j >= 0; j--){
				dp[i][j] = (s[i] == s[j]) && ((i - j < 3) || dp[i-1][j+1]);
				if (dp[i][j])
				{
					count ++;
                }
			}
		}
		return count;
    }
};

三. 最长回文子序列: 给定一个字符串s,找到其中最长的回文子序列。可以假设s的最大长度为1000。
示例 :输入:“bbbab” , 输出:4

class Solution {
public:
    int longestPalindromeSubseq(string s) {
        if(s.empty()) return 0;
        int n=s.size();
        vector<vector<int> > dp(n,vector<int>(n,0));
        for(int j=0;j<n;j++){
            dp[j][j]=1;
            for(int i=j-1;i>=0;i--){
                if(s[i]==s[j]) dp[i][j]=dp[i+1][j-1]+2;
                else dp[i][j]=max(dp[i+1][j],dp[i][j-1]);
            }
        }
        return dp[0][n-1];
    }
};

四. 回文对: 给定一组唯一的单词, 找出所有不同 的索引对(i, j),使得列表中的两个单词, words[i] + words[j] ,可拼接成回文串。
示例 :
输入: [“abcd”,“dcba”,“lls”,“s”,“sssll”]
输出: [[0,1],[1,0],[3,2],[2,4]]
解释: 可拼接成的回文串为 [“dcbaabcd”,“abcddcba”,“slls”,“llssssll”]
分析:根据回文字符串的性质,我们可以不用暴力枚举出所有字符串对。对于一个字符串对(x, y)(x,y), 若想要字符串x+y是一个回文字符串,则必须满足以下条件之一:
1.当x.length()≥y.length()时, 字符串x的y.length()长度的前缀与y的逆序相等,且字符串x去除长度为y.length()的前缀后,余下的部分也是一个回文字符串。
2.当x.length() < y.length()时,与情况一正相反。如下图所示,要分析Y在X前,Y在X后的两种情况。

在这里插入图片描述

class Solution {
public:
    bool f(string& s,int left,int right){
        while(left<right){
            if(s[left++]!=s[right--]) return false;
        }
        return true;
    }
    vector<vector<int>> palindromePairs(vector<string>& words) {
        unordered_map<string,int> m;
        set<int> s;
        int n=words.size();
        for(int i=0;i<n;i++){
            m[words[i]]=i;
            s.insert(words[i].size());
        }
        vector<vector<int>> res;
        for(int i=0;i<n;i++){
            string tmp=words[i];
            reverse(tmp.begin(),tmp.end());
            if(m.count(tmp)&&m[tmp]!=i){
                res.push_back({m[tmp],i});
            }
            int length=tmp.size();
            for(auto it=s.begin();*it!=length;it++){
                int d=*it;
                if(f(tmp,0,length-d-1)&&m.count(tmp.substr(length-d))){
                    res.push_back({i,m[tmp.substr(length-d)]});
                }
                if(f(tmp,d,length-1)&&m.count(tmp.substr(0,d))){
                    res.push_back({m[tmp.substr(0,d)],i});
                }
            }
        }
        return res;
    }
};

五. 回文排列: 给定一个字符串,判断该字符串中是否可以通过重新排列组合,形成一个回文字符串。

示例 1:输入: “code”,输出: false
示例 2:输入: “aab”,输出: true

// 只有0个或1个字符出现奇数次,其余出现偶数次
class Solution {
public:
    bool canPermutePalindrome(string s) {
        unordered_map<char, int> m;
        for(char c:s)
            m[c]+=1;
        int odd = 0;
        for(auto it = m.begin(); it!=m.end();++it)
            if(it->second % 2 == 1)
                odd ++;
        return (odd == 0) || (odd == 1);
    }
};


六、给定一个字符串 s,你可以通过在字符串前面添加字符将其转换为回文串。找到并返回可以用这种方式转换的最短回文串。
示例 1:输入: “aacecaaa”, 输出: “aaacecaaa”
示例 2:输入: “abcd”, 输出: “dcbabcd”
分析:采用字符串匹配KMP算法及求next值算法。先求s字符串首字符开始的最大回文串的长度length,拼接s串length下标后的字符串的翻转就是最短回文串。先创建临时字符串temp(s+rev(s)),再求出temp字符串的next数组,next[temp.size]就是s字符串首字符开始的最大回文串的长度。(KMP匹配的参考链接如下)
参考链接1
参考链接2

   /*思路  如对于串 abcd 想要将其变为回文串
      那么先把它逆序 然后放在前面 自然是回文了 
                                   abcd
                                   dcba
                               dcbaabcd ->是回文
      但是我们发现根本没必要放这么多在前面 因为abcd的前缀和dcab的后缀有重合(如a) 所以为了只添加最少的字符,我们在前方只需要添加不重复的即可
                                    abcd
                                 dcba
                                 dcbabcd ->依然是回文
     //为了添加的最少 我们就需要找到dcba的后缀和abcd的前缀重合的部分,且让重合部分最大即可
     //故而联想到kmp算法,它的next数组就是用来求一个串的前缀和后缀相同的长度的最大值
     //所以拼接起字符串 abcddcba 但是我们所求的前缀是不能超过中点的,因此用一个特殊字符隔开
     //           即为 abcd#dcba 这样在匹配前后缀时,相同长度就一定不会超过#号了
     //           这样问题就转化为了 求abcd#dcba的next数组 易知该串的前后缀相同时的最大长度为1
                此时的最长相同前后缀即为a 和 a  
                                     所以把后半部分除去重叠的部分拼接到前半部分即可
                            答案就是  dcbabcd
                                     大功告成!
                  
     */
    string shortestPalindrome(string s) {
        string revs = s;//存s的逆序
        int tn = s.size();//中点处,#前面的位置
        reverse(revs.begin(),revs.end());
        s = ' '+ s + '#' + revs;//让下标从1开始
        int n = s.size()-1;//实际长度
        vector<int> ne(n+1);//next数组
        for(int i = 2, j = 0; i <= n; i++){//求next数组 
            while(j&&s[i]!=s[j+1]) j = ne[j];
            if(s[i]==s[j+1]) j++;
            ne[i] = j;
        }
        return s.substr(tn+2,tn-ne[n])+s.substr(1,tn);//后半部分除去重叠后缀+前半部分
    }

七、判断一个整数是否是回文数。回文数是指正序(从左向右)和倒序(从右向左)读都是一样的整数。

示例 1:输入: 121;输出: true
示例 2: 输入: -121;输出: false
解释: 从左向右读, 为 -121 。 从右向左读, 为 121- 。因此它不是一个回文数。

class Solution {
public:
	bool isPalindrome(int x) {
		/*
        if ((x<0) || (x>10 && x % 10 == 0))
			return false;
		vector<int> num;
		while (x){
			num.push_back(x%10);
			x /= 10;
		}
		for (int i = 0, j = num.size()-1; i <= j; i++, j--){
			if (num[i] != num[j])
				return false;
		}
		return true;
        */
         if ((x<0) || (x>10 && x % 10 == 0))
			return false;
         int temp=x;
         long rs=0;
         for(;x;rs=rs*10+x%10,x/=10);
         return temp==rs;
	}
};
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

LeetCode - 回文类问题总结 的相关文章

  • 动手学数据分析 Task4

    动手学数据分析 Task4 一 可视化展示泰坦尼克号数据集中男女中生存人与死亡人数的比例图 二 可视化展示泰坦尼克号数据集中不同票价的人生存和死亡人数分布情况 三 可视化展示泰坦尼克号数据集中不同年龄的人生存与死亡人数分布情况 一 可视化展
  • Maven的基础知识

    Maven介绍 Maven 是一个项目管理和 综合工具 Maven 提供了开发人员构建一个完整的生命周期框架 开发团队可以自动完成项目的基础工具建设 Maven 使用标准的目录结构 和 默认构建生命周期 Maven是什么 它是一个 Apac

随机推荐

  • 各种绕过(MD5

    文章目录 MD5 0e开头的数组 MD5弱比较 MD5数组绕过 MD5 SQL注入 SHA1 SHA1弱比较 和 MD5弱类型比较同理 SHA1碰撞 MD5 0e开头的数组 MD5弱比较 QNKCDZO 240610708 byGcY so
  • 表设计为什么主键尽量无意义_奉上数据库表设计的十三条建议

    前言 本文总结了数据库表设计的十三条建议 这十三条建议只作为大家的参考 具体需要根据自己的项目来设计 来自 梦尘啊 链接 https juejin cn post 6902236691348586510 1 原始单据与实体之间的关系 表的设
  • Go:go mod vendor 使用

    Go go mod vendor 使用 1 背景 我们基于 go mod 机制来管理我们项目的依赖库版本 其中 go mod 记录了依赖库版本信息 一般第三方依赖库 包括公司内网gitlab上的依赖库 其源码都不被包含在我们的项目内部 而是
  • 5.自动装配:autowire=“byName“ or “byType“ + 使用注解【@Autowired 、@Qualifier、 @Resource】

    文章目录 自动装配说明 本博客环境搭建 自动装配 autowire byName 按名称自动装配 autowire byType 按类型自动装配 使用注解 1 Autowired 按类型自动转配的 不支持id匹配 2 Qualifier 不
  • hypertable管理当前rangserver和历史rangserver

    purge old log files void OperationRecoveryBlocker execute HT INFOF Entering RecoveryBlocker lld threadid d Lld header id
  • Docker安装

    镜像 Docker 镜像 Image 就是一个只读的模板 镜像可以用来创建 Docker 容器 一个镜像可以创建很多容器 它也相当于是一个root文件系统 比如官方镜像 centos 7 就包含了完整的一套 centos 7 最小系统的 r
  • ns2编程小技巧(转)

    1 tcl脚本传入一个int变量给c 代码在command解析里 int nodenum atoi argv 2 printf d nodenum 2 在nam中输出结果 Tcl instance evalf ns trace annota
  • Ubuntu下配置VScode及LeetCode,开始撸代码

    Ubuntu20 04下配置VScode及LeetCode 开始撸代码 一 配置VScode环境 1 软件下载 2 软件安装及启动 3 C 基础插件的安装 4 配置软件内部Debug 5 配置内部Debug工具时的异常 正常请跳过此步 6
  • JS获取本地图片和网络图片的宽高尺寸和存储大小

    最新更新时间 2020年07月08日09 13 28 猛戳 查看我的博客地图 总有你意想不到的惊喜 本文内容 图片作为一种记录信息的载体 比文本更加生动 比视频更加精简 在日常生活中的用处很大 作为前端开发人员 操作图片的场景非常多 本文记
  • 跨域产生原因和跨域解决方案

    一 为什么会出现跨域问题 出于浏览器的同源策略限制 同源策略是一种约定 它是浏览器最核心也就是最基本的安全功能 如果缺少了同源策略 浏览器的正常功能会受到影响 可以说WEB是构建在同源策略基础之上的 浏览器只是针对同源策略的一种实现 同源策
  • 有限元方法的核心思想是什么?

    有限元方法的核心思想是什么 有限元方法似乎是在不断地简化着什么 请问有限元方法的核心思想是什么 在哪些层面对方程做了简化 每一次简化的依据和思路是什么 2 条评论 按投票排序 按时间排序 31 个回答 菲兹 睡眠厌倦患者 138 人赞同 有
  • vue3+ts+setup获取全局变量getCurrentInstance

    前言 vue3的 setup中是获取不到this的 为此官方提供了特殊的方法 让我们可以使用this 达到我们获取全局变量的目的 但是在使用typescript的时候 就会有一些新的问题产生 这里来做一个整理 vue3官方提供的方法 1 引
  • ChatGPT、New Bing、文心一言、通义千问等 AI 工具到底哪个更AI? - 第二期

    文章目录 前言 选手介绍 ChatGPT New Bing 文心一言 钉钉的文档AI 通义千问 Stable Diffusion 文心一格 前言 本次是上次文章的后续 经历了这么久的时间 我也是在几个月前拿到了通义千问的测试资格 本次参加的
  • 密码爆破漏洞详解——黑客必修入门操作( 建议收藏 )

    隔壁老张 狗剩啊 隔壁xx村的王姐家的女娃好漂亮 我想盗她qq啊 你帮我个忙呗 狗剩 我不会呀 村里大妈 那个狗剩啊 连盗个qq号都不会 他妈还好意思说他是学网络安全当黑客的 密码爆破介绍 密码爆破又叫 暴力猜解 简单来说就是将密码逐个尝试
  • 第四章:进击,拿到Web最高权限

    1 根据前关已经得到了cookie 现在需要修改cookie达到登录系统的目的 2 打开网站 以谷歌浏览器为例 F12打开控制台 找到Application 对图中3 4的值进行修改 修改的内容为你获取到的cookie的内容 3 4分别对应
  • Unity XCode 拨号和一键加群

    拨号 void CallPhone const char iphone NSString nsIphone NSString stringWithFormat tel s iphone NSLog nsIphone NSURL url NS
  • centos如何查看linux内核,版本号

    root localhost uname a Linux localhost localdomain 3 10 0 957 el7 x86 64 1 SMP Thu Nov 8 23 39 32 UTC 2018 x86 64 x86 64
  • CSDN博客的RSS订阅---使用foxmail订阅

    CSDN博客有RSS订阅 使用foxmail订阅 好处是可以第一时间邮件通知 订阅自己的博客可以作为备份 foxmail订阅方法 CSDN博客有RSS订阅 使用foxmail订阅 好处是可以第一时间邮件通知 订阅自己的博客 可以作为备份 f
  • Python爬虫教程:包图网免费付费素材爬取【附源码】

    包图网大家都知道吧 集齐海量设计素材 十分好用 可惜太贵了 今天就带大家使用Python 爬虫爬取这些素材并且保存到本地 抓取一个网站的内容 我们需要从以下几方面入手 1 如何抓取网站的下一页链接 2 目标资源是静态还是动态 视频 图片等
  • LeetCode - 回文类问题总结

    子串与子序列 1 字符子串 指的是字符串中连续的n个字符 如abcdefg中 ab cde fg等都属于它的字串 2 字符子序列 指的是字符串中不一定连续但先后顺序一致的n个字符 即可以去掉字符串中的部分字符 但不可改变其前后顺序 如abc