1. 题目:

  Given a string S, find the longest palindromic substring in S. You may assume that the maximum length of S is 1000, and there exists one unique longest palindromic substring.

注:

palindromic substring :回文序列,如:aba,abba 等。

2.1   C++    暴力解决—— 时间复杂度O(N³)

思路:

(1).  构造一个map,存储原字符出现的所有位置;

(2). 从头到位扫描字符串,根据map中的位置,选取子字符串,判断是否为回文序列

class Solution {
public:
    string longestPalindrome(string s) {
        unsigned long long string_len=s.length();
        if(string_len==0)
            return "";
        if(string_len==1)
            return s;
        string current_str="",longest_str="";
        unsigned long long current_len=0,longest_len=0;
        map<char,vector<unsigned long long> >char_pos_map;
         
        for(int i=0;i<string_len;i++){
            map<char,vector<unsigned long long> >::iterator char_pos_map_it=char_pos_map.find(s[i]);  
            if(char_pos_map_it==char_pos_map.end()) {   
                vector<unsigned long long> pos_list;   
                pos_list.push_back(i);   
                char_pos_map.insert(pair<char, vector<unsigned long long > >((char)s[i],pos_list));   
            } else {   
                vector<unsigned long long> & pos_list=char_pos_map_it->second;   
                pos_list.push_back(i);   
            }   
        }                                      //map存储每个字符出现的位置
         
       
        for(int index_head = 0;index_head<string_len;index_head++) {   
            std::map<char, vector<unsigned long long > >::iterator it = char_pos_map.find(s[index_head]);   
            if( it->second.size()==1) {   
                current_len = 1;   
                current_str = s[index_head];   
                if(current_len>longest_len) {   
                      longest_str = current_str;   
                      longest_len = current_len;                          //只出现一次的字符         
                }

} else {                       
                vector<unsigned long long> & tmp_vec = it->second;                   
                unsigned long long index_num =  tmp_vec.size();   
                unsigned long long tmp_index_head =  index_head;   
                for(long long j=(long long)(index_num-1);j>=0;j--) {   
                    tmp_index_head = index_head;   
                    unsigned long long tmp_index_tail = tmp_vec[j];   
                     
                    if(tmp_index_tail<tmp_index_head)   
                        continue;   
                    current_len = tmp_index_tail-tmp_index_head+1;   
                    if( current_len==0 || current_len < longest_len)   
                        continue;   
                         
                    current_str = s.substr(tmp_index_head, current_len);        //取子字符串,验证是否为回文字符
                    while( ((long long)(tmp_index_tail-tmp_index_head)>=1) && (s[tmp_index_tail]==s[tmp_index_head]) ) {

tmp_index_head++;   
                        tmp_index_tail--;   
                    }

if( ((long long)(tmp_index_tail-tmp_index_head)==-1) || (tmp_index_tail-tmp_index_head==0) ){       //奇数  偶数个字符的情况
                        longest_len = current_len;   
                        longest_str = current_str;   
                    }   
                       
                }   
            }   
        }   
        return longest_str;   
    }   
};

2.2  动态规划

删除暴力解法中有很多重复的判断。很容易想到动态规划,时间复杂度O(n^2),空间O(n^2),动态规划方程如下:

  • dp[i][j] 表示子串s[i…j]是否是回文
  • 初始化:dp[i][i] = true (0 <= i <= n-1);  dp[i][i-1] = true (1 <= i <= n-1); 其余的初始化为false
  • dp[i][j] = (s[i] == s[j] && dp[i+1][j-1] == true)

在动态规划中保存最长回文的长度及起点即可

 
 
class Solution {
public:
    string longestPalindrome(string s) {
        const int len = s.size();
        if(len <= 1)return s;
        bool dp[len][len];               //dp[i][j]表示s[i..j]是否是回文
        memset(dp, 0, sizeof(dp));      //初始化为0
        int resLeft = 0, resRight = 0; 
        dp[0][0] = true;
 
        for(int i = 1; i < len; i++)
        {
            dp[i][i] = true;
            dp[i][i-1] = true;           //这个初始化容易忽略,当k=2时要用到
        }
 
        for(int k = 2; k <= len; k++)           //外层循环:枚举子串长度
            for(int i = 0; i <= len-k; i++)     //内层循环:枚举子串起始位置
            {
                if(s[i] == s[i+k-1] && dp[i+1][i+k-2])
                {
                    dp[i][i+k-1] = true;
                    if(resRight-resLeft+1 < k)
                    {
                        resLeft = i;
                        resRight = i+k-1;
                    }
                }
            }
        return s.substr(resLeft, resRight-resLeft+1);
    }
};

2.3 从中间向两边展开,时间复杂度O(n^2),空间O(1)

  回文字符串显然有个特征是沿着中心那个字符轴对称。比如aha沿着中间的h轴对称,a沿着中间的a轴对称。那么aa呢?沿着中间的空字符''轴对称。所以对于长度为奇数的回文字符串,它沿着中心字符轴对称,对于长度为偶数的回文字符串,它沿着中心的空字符轴对称。对于长度为N的候选字符串,我们需要在每一个可能的中心点进行检测以判断是否构成回文字符串,这样的中心点一共有2N-1个(2N-1=N-1 + N)。检测的具体办法是,从中心开始向两端展开,观察两端的字符是否相同

class Solution {
public:
    string longestPalindrome(string s) {
        const int len = s.size();
        if(len <= 1)return s;
        int start, maxLen = 0;
        for(int i = 1; i < len; i++)
        {
            //寻找以i-1,i为中点偶数长度的回文
            int low = i-1, high = i;
            while(low >= 0 && high < len && s[low] == s[high])
            {
                low--;
                high++;
            }
            if(high - low - 1 > maxLen)
            {
                maxLen = high - low -1;
                start = low + 1;
            }
             
            //寻找以i为中心的奇数长度的回文
            low = i- 1; high = i + 1;
            while(low >= 0 && high < len && s[low] == s[high])
            {
                low--;
                high++;
            }
            if(high - low - 1 > maxLen)
            {
                maxLen = high - low -1;
                start = low + 1;
            }
        }
        return s.substr(start, maxLen);
    }
};

java

两侧比较:

public class LongestPalindromicSubString1 {  

    /**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
System.out.println(longestPalindrome1("babcbabcbaccba"));
} public static String longestPalindrome1(String s) { int maxPalinLength = 0;
String longestPalindrome = null;
int length = s.length(); // check all possible sub strings
for (int i = 0; i < length; i++) {
for (int j = i + 1; j < length; j++) {
int len = j - i;
String curr = s.substring(i, j + 1);
if (isPalindrome(curr)) {
if (len > maxPalinLength) {
longestPalindrome = curr;
maxPalinLength = len;
}
}
}
} return longestPalindrome;
} public static boolean isPalindrome(String s) { for (int i = 0; i < s.length() - 1; i++) {
if (s.charAt(i) != s.charAt(s.length() - 1 - i)) {
return false;
}
} return true;
}
}

动态规划:

public class LongestPalindromicSubString2 {  

    public static String longestPalindrome2(String s) {
if (s == null)
return null; if(s.length() <=1)
return s; int maxLen = 0;
String longestStr = null; int length = s.length(); int[][] table = new int[length][length]; //every single letter is palindrome
for (int i = 0; i < length; i++) {
table[i][i] = 1;
}
printTable(table); //e.g. bcba
//two consecutive same letters are palindrome
for (int i = 0; i <= length - 2; i++) {
//System.out.println("i="+i+" "+s.charAt(i));
//System.out.println("i="+i+" "+s.charAt(i+1));
if (s.charAt(i) == s.charAt(i + 1)){
table[i][i + 1] = 1;
longestStr = s.substring(i, i + 2);
}
}
System.out.println(longestStr);
printTable(table);
//condition for calculate whole table
for (int l = 3; l <= length; l++) {
for (int i = 0; i <= length-l; i++) {
int j = i + l - 1;
if (s.charAt(i) == s.charAt(j)) {
table[i][j] = table[i + 1][j - 1];
if (table[i][j] == 1 && l > maxLen)
longestStr = s.substring(i, j + 1); } else {
table[i][j] = 0;
}
printTable(table);
}
} return longestStr;
}
public static void printTable(int[][] x){
for(int [] y : x){
for(int z: y){
//System.out.print(z + " ");
}
//System.out.println();
}
//System.out.println("------");
}
public static void main(String[] args) {
System.out.println(longestPalindrome2("1263625"));//babcbabcbaccba
}
}

最新文章

  1. Android 进程通信机制之 AIDL
  2. SharePoint文档库,如何在新窗口打开中的文件
  3. (转)如何将数据库从SQL Server迁移到MySQL
  4. mysql的binlog安全删除
  5. 04_过滤器Filter_03_多个Filter的执行顺序
  6. VMware虚拟机中如何安装VMWare-Tools详解
  7. .NET基础拾遗(3)字符串、集合和流2
  8. Google AdSense的CPC点击单价超百度联盟(2014)
  9. 如何书写高效的css样式
  10. leetcode — remove-duplicates-from-sorted-list
  11. spring-boot-devtools在Idea中热部署方法
  12. nc_netcat命令
  13. springboot 双数据源+aop动态切换
  14. luogu P4314 CPU监控
  15. Linux 安装搭建 tftpd 服务器
  16. 1657 Distance on Chessboard(简单计算题)
  17. ubuntu php 安装
  18. (转)Java程序员应该知道的10个调试技巧
  19. RabbitMQ与java、Spring结合实例详细讲解
  20. javassist示例

热门文章

  1. 在Android中使用Protocol Buffers(下篇)
  2. ProtoBuf练习(五)
  3. 【原创】智能合约安全事故回顾分析(1):The Dao事件
  4. 洛谷P2580(trie)
  5. MCP|LQD|Data-independent acquisition improves quantitative cross-linking mass spectrometry (DIA方法可提升交联质谱定量分析)
  6. PyCharm专业版安装(2018年Windows版)
  7. iOS常用设计模式——工厂方法(简单工厂模式,工厂方法模式, 抽象工厂模式)
  8. [SCOI2010]连续攻击游戏 BZOJ1854 二分图匹配
  9. 运算符优先级 (JavaScript)
  10. jquery——事件冒泡、事件委托