• 最长回文子串(Longest Palindromic substring)


    什么叫回文串

    就是正读和反读都是一样的字符串,比如aba,abba,cdc像这样的字符串都是回文字符串

     暴力破解法来查找最长的回文子串

    这个图解的意思就是我们要拿到每一个右边的数,然后与左边的数一一匹配

    下面看一下java的实现代码

    1. package com.pxx;
    2. /**
    3. * Created by Administrator on 2023/9/11.
    4. */
    5. public class Test2 {
    6. public static String longestPalindrome(String s) {
    7. if (s == null) {
    8. return null;
    9. }
    10. //从最右边才是最长的,越往里面走,越短
    11. for (int len = s.length(); len >= 1; len--) {
    12. //这里i + len是保证你每一个回文串的长度来整体字符串长度之内
    13. for (int start = 0; start + len <= s.length(); start++) {
    14. if (isPalindrome(s,start,start + len - 1)) {
    15. return s.substring(start,start + len);
    16. }
    17. }
    18. }
    19. //没有结果就返回空串
    20. return "";
    21. }
    22. //直接判断是否是回文数
    23. private static boolean isPalindrome(String s,int left,int right) {
    24. while (left < right && s.charAt(left) == s.charAt(right)) {
    25. left++;
    26. right--;
    27. }
    28. //如果是回文数的情况下,肯定会造成left >= right的,某种情况来说,left == right程序就已经截止了
    29. return left >= right;//为真就是回文串,为假就不是回文串
    30. }
    31. public static void main(String[] args) {
    32. String res = longestPalindrome("abcdzdcab");
    33. System.out.println(res);
    34. }
    35. }

    下面是c语言代码实现

    1. #include
    2. #include
    3. #include
    4. // 判断是否是回文字符串
    5. bool isPalindrome(const char* s, int left, int right) {
    6. while (left < right && s[left] == s[right]) {
    7. left++;
    8. right--;
    9. }
    10. return left >= right;
    11. }
    12. // 查找最长回文子串
    13. const char* longestPalindrome(const char* s) {
    14. if (s == NULL) {
    15. return NULL;
    16. }
    17. for(int len = strlen(s); len >= 1; len--) {
    18. for(int start = 0; start + len <= strlen(s); start++) {
    19. if(isPalindrome(s,start,start + len - 1)) {
    20. char* result = (char*)malloc(sizeof(char) * (start + len));
    21. strncpy(result, s + start, start + len - 2);
    22. result[start + len] = '\0';
    23. return result;
    24. }
    25. }
    26. }
    27. return "";
    28. }
    29. int main() {
    30. const char* input = "abcdzdcab";
    31. const char* result = longestPalindrome(input);
    32. printf("Input: %s\n", input);
    33. printf("Longest palindrome: %s\n", result);
    34. free((void*)result); // 释放动态分配的内存
    35. return 0;
    36. }

    上面这个算法的时间复杂度是O(n^3) 

     

    基于中心点的枚举法Enumeration来实现查找最长子串

    实现原理

     

    上面是大体实现,具体要分奇数回文串来看或者偶数回文串来看 

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

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

     下面是java代码实现

    1. public class Enumeration {
    2. //主体函数
    3. //拿到字符串里面的最长回文字符串
    4. public static String longestPolindrom(String s) {
    5. //安全性检查
    6. if(s == null) {
    7. return null;
    8. }
    9. //定义一个我们需要返回的字符串
    10. String longest = "";
    11. //遍历整个字符串然后检查
    12. for(int i = 0; i < s.length(); i++) {
    13. //这里是奇数部分的查找
    14. String oddPolindrome = getPolindromeFrom(s,i,i);//之前分析过,奇数其实就是固定一点,左右散发,这里是i
    15. //判定一下是否把得到的回文串给替换不
    16. if (longest.length() < oddPolindrome.length()) {//小于返回的就替换,因为我们要找最长的
    17. longest = oddPolindrome;//直接把这个字符串给替换
    18. }
    19. //这里是偶数串的查找
    20. String evenPolindrome = getPolindromeFrom(s,i,i+1);//偶数串就不能固定一个点
    21. if (longest.length() < evenPolindrome.length()) {
    22. longest = evenPolindrome;
    23. }
    24. }
    25. //上面循环完之后返回
    26. return longest;
    27. }
    28. //得到回文字符串
    29. public static String getPolindromeFrom(String s, int left, int right) {
    30. //双指针,相向而行的一个双指针
    31. while (left >= 0 && right < s.length()) {
    32. if (s.charAt(left) != s.charAt(right)) {
    33. break;//先break掉
    34. }
    35. left--;
    36. right++;
    37. }
    38. //最后直接截断
    39. //这个截断是包头不包尾
    40. //left这个位置已经是不相等的位置了
    41. return s.substring(left + 1,right);
    42. }
    43. public static void main(String[] args) {
    44. String res = longestPolindrom("abcdzdcab");
    45. System.out.println(res);
    46. }
    47. }

    运行结果:

     下面是c++代码实现

    1. #include
    2. #include
    3. #include
    4. using namespace std;
    5. //写一个函数返回回文字符串的长度
    6. int expand_around_center(const string& s,int left,int right)
    7. {
    8. int len = s.length();
    9. while (left >= 0 && right < len && s[left] == s[right]) {
    10. left--;//往左边扩展
    11. right++;//往右边扩展
    12. }
    13. //一旦上面不满足了,就返回这个长度
    14. return right - left -1;
    15. }
    16. //主函数:查找最长的回文子串
    17. string longest_palindrome(const string& s)
    18. {
    19. int start = 0, end = 0;//初始化最长回文子串的起始位置与结束位置
    20. int len = s.length();
    21. for (int i = 0; i < len; i++) {
    22. //开始轮替,这里分为奇数轮替与偶数的轮替
    23. int len1 = expand_around_center(s,i,i);
    24. int len2 = expand_around_center(s,i,i + 1);
    25. //上面都会返回文子串的长度,也有可能返回0,我们就取其中最大的就行了
    26. int max_len = max(len1,len2);//依赖头文件
    27. //如果当前返回的长度 > 之前记录的长度
    28. //需要更新起始位置与结束位置
    29. //这段代码直接背下来
    30. if (max_len > end - start) {
    31. start = i - (max_len - 1) / 2;
    32. end = i + max_len / 2;
    33. }
    34. }
    35. //上面整体循环完了之后,start与end都是边界,然后用substr截取
    36. return s.substr(start,end - start + 1);//为什么加1,因为end -start就会少一个数 2 4 =》 4 - 2 + 1
    37. }
    38. int main()
    39. {
    40. string input = "abcdzdcab";
    41. string result = longest_palindrome(input);
    42. printf("input : %s\n",input.c_str());
    43. //这是c++的方法,可以理解为把string->char*,然后让printf进行打印
    44. printf("Longest palindrom: %s\n",result.c_str());
    45. return 0;
    46. }

    运行结果:

    下面用图解的方式对c++的部分进行分析

     解析1:right  - left - 1

    解析2:

     

    有几个小的知识点我得说一下:

    第一个:关于-1/2=0,本来应该是-0.5,但是1与2都是整型嘛,然后后面就截断了 0不占符号位,如果还是-4/2 = -2,这个时候就得有符号位

    第二个:printf()不能打印char*的c语言类型的字符串,所以字符串可以调用c_str()函数变成包含了c语言指针的字符串

    那如果我们用c语言处理呢,就把上面代码修改一下就可以了下面看代码

    1. #include
    2. #include
    3. #include
    4. // 辅助函数:查找以left和right为中心的最长回文子串
    5. int expandAroundCenter(char *s, int left, int right) {
    6. int len = strlen(s);
    7. while (left >= 0 && right < len && s[left] == s[right]) {
    8. left--;
    9. right++;
    10. }
    11. return right - left - 1;//这里返回回文串的长度
    12. }
    13. // 主函数:查找最长回文子串
    14. char *longestPalindrome(char *s) {
    15. int start = 0; // 最长回文子串的起始位置
    16. int end = 0; // 最长回文子串的结束位置
    17. int len = strlen(s);
    18. for (int i = 0; i < len; i++) {
    19. // 以每个字符为中心,分奇数和偶数长度回文子串两种情况进行扩展
    20. int len1 = expandAroundCenter(s, i, i);
    21. int len2 = expandAroundCenter(s, i, i + 1);
    22. // 取两种情况中的较长者
    23. int maxLen = len1 > len2 ? len1 : len2;
    24. // 如果当前回文子串的长度大于之前记录的最长回文子串长度
    25. // 则更新起始和结束位置
    26. if (maxLen > end - start) {
    27. start = i - (maxLen - 1) / 2;
    28. end = i + maxLen / 2;
    29. }
    30. }
    31. // 根据起始和结束位置截取最长回文子串
    32. char *result = (char*)malloc(sizeof(char) * (end - start + 2));
    33. strncpy(result, s + start, end - start + 1);
    34. result[end - start + 1] = '\0';
    35. return result;
    36. }
    37. int main() {
    38. char input[] = "babad";
    39. char *result = longestPalindrome(input);
    40. printf("Input: %s\n", input);
    41. printf("Longest Palindrome: %s\n", result);
    42. free(result); // 释放分配的内存
    43. return 0;
    44. }

    下面是对一部分核心代码的讲解

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

    先说到这

  • 相关阅读:
    B - Extended Traffic(边权带负,spfa并且判断负环)
    Linux常用命令
    Apache Hadoop(一)
    Shell 脚本编程(二) —— 条件判断 (test命令) + 多路分支语句(if 、case)
    机器学习-决策树
    Java集合自定义字段排序
    银行利率bp是什么意思,利率bp怎么换算
    SSM美众针纺有限公司人事管理毕业设计-附源码051708
    E: Unable to locate package libboost-all-dev
    Spring整合Mybatis
  • 原文地址:https://blog.csdn.net/Pxx520Tangtian/article/details/132780847