什么叫回文串
就是正读和反读都是一样的字符串,比如aba,abba,cdc像这样的字符串都是回文字符串
暴力破解法来查找最长的回文子串

这个图解的意思就是我们要拿到每一个右边的数,然后与左边的数一一匹配
下面看一下java的实现代码
- package com.pxx;
-
- /**
- * Created by Administrator on 2023/9/11.
- */
- public class Test2 {
-
- public static String longestPalindrome(String s) {
- if (s == null) {
- return null;
- }
-
- //从最右边才是最长的,越往里面走,越短
- for (int len = s.length(); len >= 1; len--) {
- //这里i + len是保证你每一个回文串的长度来整体字符串长度之内
- for (int start = 0; start + len <= s.length(); start++) {
- if (isPalindrome(s,start,start + len - 1)) {
- return s.substring(start,start + len);
- }
- }
- }
- //没有结果就返回空串
- return "";
- }
-
- //直接判断是否是回文数
- private static boolean isPalindrome(String s,int left,int right) {
- while (left < right && s.charAt(left) == s.charAt(right)) {
- left++;
- right--;
- }
- //如果是回文数的情况下,肯定会造成left >= right的,某种情况来说,left == right程序就已经截止了
- return left >= right;//为真就是回文串,为假就不是回文串
- }
-
- public static void main(String[] args) {
- String res = longestPalindrome("abcdzdcab");
- System.out.println(res);
- }
- }
下面是c语言代码实现
- #include
- #include
- #include
-
- // 判断是否是回文字符串
- bool isPalindrome(const char* s, int left, int right) {
- while (left < right && s[left] == s[right]) {
- left++;
- right--;
- }
- return left >= right;
- }
-
- // 查找最长回文子串
- const char* longestPalindrome(const char* s) {
- if (s == NULL) {
- return NULL;
- }
- for(int len = strlen(s); len >= 1; len--) {
- for(int start = 0; start + len <= strlen(s); start++) {
- if(isPalindrome(s,start,start + len - 1)) {
- char* result = (char*)malloc(sizeof(char) * (start + len));
- strncpy(result, s + start, start + len - 2);
- result[start + len] = '\0';
- return result;
- }
- }
- }
-
- return "";
- }
-
- int main() {
- const char* input = "abcdzdcab";
- const char* result = longestPalindrome(input);
-
- printf("Input: %s\n", input);
- printf("Longest palindrome: %s\n", result);
-
- free((void*)result); // 释放动态分配的内存
-
- return 0;
- }
上面这个算法的时间复杂度是O(n^3)
基于中心点的枚举法Enumeration来实现查找最长子串
实现原理
上面是大体实现,具体要分奇数回文串来看或者偶数回文串来看

奇数部分代码实现原理分析

偶数部分代码实现原理分析

下面是java代码实现
- public class Enumeration {
-
- //主体函数
- //拿到字符串里面的最长回文字符串
- public static String longestPolindrom(String s) {
- //安全性检查
- if(s == null) {
- return null;
- }
- //定义一个我们需要返回的字符串
- String longest = "";
- //遍历整个字符串然后检查
- for(int i = 0; i < s.length(); i++) {
- //这里是奇数部分的查找
- String oddPolindrome = getPolindromeFrom(s,i,i);//之前分析过,奇数其实就是固定一点,左右散发,这里是i
- //判定一下是否把得到的回文串给替换不
- if (longest.length() < oddPolindrome.length()) {//小于返回的就替换,因为我们要找最长的
- longest = oddPolindrome;//直接把这个字符串给替换
- }
- //这里是偶数串的查找
- String evenPolindrome = getPolindromeFrom(s,i,i+1);//偶数串就不能固定一个点
- if (longest.length() < evenPolindrome.length()) {
- longest = evenPolindrome;
- }
- }
-
- //上面循环完之后返回
- return longest;
-
- }
-
- //得到回文字符串
- public static String getPolindromeFrom(String s, int left, int right) {
- //双指针,相向而行的一个双指针
- while (left >= 0 && right < s.length()) {
- if (s.charAt(left) != s.charAt(right)) {
- break;//先break掉
- }
- left--;
- right++;
-
- }
- //最后直接截断
- //这个截断是包头不包尾
- //left这个位置已经是不相等的位置了
- return s.substring(left + 1,right);
- }
-
- public static void main(String[] args) {
- String res = longestPolindrom("abcdzdcab");
- System.out.println(res);
- }
- }
运行结果:

下面是c++代码实现
- #include
- #include
- #include
-
-
- using namespace std;
-
- //写一个函数返回回文字符串的长度
- int expand_around_center(const string& s,int left,int right)
- {
- int len = s.length();
- while (left >= 0 && right < len && s[left] == s[right]) {
- left--;//往左边扩展
- right++;//往右边扩展
- }
- //一旦上面不满足了,就返回这个长度
- return right - left -1;
- }
-
- //主函数:查找最长的回文子串
- string longest_palindrome(const string& s)
- {
- int start = 0, end = 0;//初始化最长回文子串的起始位置与结束位置
-
- int len = s.length();
- for (int i = 0; i < len; i++) {
- //开始轮替,这里分为奇数轮替与偶数的轮替
- int len1 = expand_around_center(s,i,i);
- int len2 = expand_around_center(s,i,i + 1);
-
- //上面都会返回文子串的长度,也有可能返回0,我们就取其中最大的就行了
- int max_len = max(len1,len2);//依赖头文件
-
- //如果当前返回的长度 > 之前记录的长度
- //需要更新起始位置与结束位置
- //这段代码直接背下来
- if (max_len > end - start) {
- start = i - (max_len - 1) / 2;
- end = i + max_len / 2;
- }
- }
-
- //上面整体循环完了之后,start与end都是边界,然后用substr截取
- return s.substr(start,end - start + 1);//为什么加1,因为end -start就会少一个数 2 4 =》 4 - 2 + 1
- }
-
- int main()
- {
- string input = "abcdzdcab";
- string result = longest_palindrome(input);
- printf("input : %s\n",input.c_str());
- //这是c++的方法,可以理解为把string->char*,然后让printf进行打印
- printf("Longest palindrom: %s\n",result.c_str());
- return 0;
- }
运行结果:

下面用图解的方式对c++的部分进行分析
解析1:right - left - 1
解析2:


有几个小的知识点我得说一下:
第一个:关于-1/2=0,本来应该是-0.5,但是1与2都是整型嘛,然后后面就截断了 0不占符号位,如果还是-4/2 = -2,这个时候就得有符号位
第二个:printf()不能打印char*的c语言类型的字符串,所以字符串可以调用c_str()函数变成包含了c语言指针的字符串
那如果我们用c语言处理呢,就把上面代码修改一下就可以了下面看代码
- #include
- #include
- #include
-
- // 辅助函数:查找以left和right为中心的最长回文子串
- int expandAroundCenter(char *s, int left, int right) {
- int len = strlen(s);
- while (left >= 0 && right < len && s[left] == s[right]) {
- left--;
- right++;
- }
- return right - left - 1;//这里返回回文串的长度
- }
-
- // 主函数:查找最长回文子串
- char *longestPalindrome(char *s) {
- int start = 0; // 最长回文子串的起始位置
- int end = 0; // 最长回文子串的结束位置
-
- int len = strlen(s);
- for (int i = 0; i < len; i++) {
- // 以每个字符为中心,分奇数和偶数长度回文子串两种情况进行扩展
- int len1 = expandAroundCenter(s, i, i);
- int len2 = expandAroundCenter(s, i, i + 1);
-
- // 取两种情况中的较长者
- int maxLen = len1 > len2 ? len1 : len2;
-
- // 如果当前回文子串的长度大于之前记录的最长回文子串长度
- // 则更新起始和结束位置
- if (maxLen > end - start) {
- start = i - (maxLen - 1) / 2;
- end = i + maxLen / 2;
- }
- }
-
- // 根据起始和结束位置截取最长回文子串
- char *result = (char*)malloc(sizeof(char) * (end - start + 2));
- strncpy(result, s + start, end - start + 1);
- result[end - start + 1] = '\0';
-
- return result;
- }
-
- int main() {
- char input[] = "babad";
- char *result = longestPalindrome(input);
-
- printf("Input: %s\n", input);
- printf("Longest Palindrome: %s\n", result);
-
- free(result); // 释放分配的内存
-
- return 0;
- }
下面是对一部分核心代码的讲解

这个算法的时间复杂度是O(n^2)
先说到这