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.
时间 O(n^3) 空间 O(1)php
暴力法就是穷举全部子字符串的可能,而后依次按位判断其是不是回文,并更新结果。虽然其时间复杂度很高,但它对空间的要求很低。java
public class Solution { public String longestPalindrome(String s) { int maxLength = 0; int maxStart = 0; int len = s.length(); //i是字符串长度 for(int i = 0; i < len; i++){ //j是字符串起始位置 for(int j = 0; j < len - i; j++){ //挨个判断是否回文 if(isPalindrome(s,i,j) && (i+1)>maxLength){ maxLength = i + 1; maxStart = j; } } } return s.substring(maxStart,maxStart + maxLength); } private isPalindrome(String s, int i, int j){ int left = j; int right = j + i; while(left<right){ if(s.charAt(left)!=s.charAt(right)){ return false; } left++; right--; } return true; } }
时间 O(n^2) 空间 O(n^2)python
根据回文的特性,一个大回文按比例缩小后的字符串也一定是回文,好比ABCCBA,那BCCB确定也是回文。因此咱们能够根据动态规划的两个特色:第一大问题拆解为小问题,第二重复利用以前的计算结果,来解答这道题。那如何划分小问题呢,咱们能够先把全部长度最短为1的子字符串计算出来,根据起始位置从左向右,这些一定是回文。而后计算全部长度为2的子字符串,再根据起始位置从左向右。到长度为3的时候,咱们就能够利用上次的计算结果:若是中心对称的短字符串不是回文,那长字符串也不是,若是短字符串是回文,那就要看长字符串两头是否同样。这样,一直到长度最大的子字符串,咱们就把整个字符串集穷举完了,可是因为使用动态规划,使计算时间从O(N^3)减小到O(n^2)。算法
public class Solution { public String longestPalindrome(String s) { int maxLength = 0; int maxStart = 0; int len = s.length(); boolean[][] dp = new boolean[len][len]; //i是字符串长度 for(int i = 0; i < len; i++){ //j是字符串起始位置 for(int j = 0; j < len - i; j++){ if(i==0||i==1){ //若是字符串长度为0,一定为回文 dp[j][j+i] = true; } else if(s.charAt(j+i)==s.charAt(j)){ //若是左右两端相等,那只要中心对称子字符串是回文就是回文 dp[j][j+i] = dp[j+1][j+i-1]; } else { //不然不是回文 dp[j][j+i] = false; } if(dp[j][j+i] && i > maxLength){ maxLength = i + 1; maxStart = j; } } } return s.substring(maxStart,maxStart + maxLength); } }
时间 O(n^2) 空间 O(1)数组
动态规划虽然优化了时间,但也浪费了空间。实际上咱们并不须要一直存储全部子字符串的回文状况,咱们须要知道的只是中心对称的较小一层是不是回文。因此若是咱们从小到大连续以某点为个中心的全部子字符串进行计算,就能省略这个空间。 这种解法中,外层循环遍历的是子字符串的中心点,内层循环则是从中心扩散,一旦不是回文就再也不计算其余以此为中心的较大的字符串。因为中心对称有两种状况,一是奇数个字母以某个字母对称,而是偶数个字母以两个字母中间为对称,因此咱们要分别计算这两种对称状况。app
public class Solution { String longest = ""; public String longestPalindrome(String s) { for(int i = 0; i < s.length(); i++){ //计算奇数子字符串 helper(s, i, 0); //计算偶数子字符串 helper(s, i, 1); } return longest; } private void helper(String s, int idx, int offset){ int left = idx; int right = idx + offset; while(left>=0 && right<s.length() && s.charAt(left)==s.charAt(right)){ left--; right++; } // 截出当前最长的子串 String currLongest = s.substring(left + 1, right); // 判断是否比全局最长还长 if(currLongest.length() > longest.length()){ longest = currLongest; } } }
2018/2优化
class Solution: def longestPalindrome(self, s): """ :type s: str :rtype: str """ maxStr = '' for index in range(0, len(s)): sub1 = self.spreadFromCenter(s, index, 0) sub2 = self.spreadFromCenter(s, index, 1) if len(sub1) > len(maxStr): maxStr = sub1 if len(sub2) > len(maxStr): maxStr = sub2 return maxStr def spreadFromCenter(self, string, centerIndex, offset): leftIndex = centerIndex rightIndex = centerIndex + offset length = len(string) while leftIndex >= 0 and rightIndex < length and string[leftIndex] == string[rightIndex]: leftIndex = leftIndex - 1 rightIndex = rightIndex + 1 leftIndex = leftIndex + 1 substring = string[leftIndex:rightIndex] return substring
时间 O(n) 空间 O(n)ui
关于时间复杂度的证实:http://www.zhihu.com/question...code
Manacher算法是很是经典的计算连续下标回文的算法。它利用了回文的对称性,更具体的来讲,是回文内回文的对称性,来解决这个问题。
参见:http://www.felix021.com/blog/...blog
public class Solution { public String longestPalindrome(String s) { if(s.length()<=1){ return s; } // 预处理字符串,避免奇偶问题 String str = preProcess(s); // idx是当前可以向右延伸的最远的回文串中心点,随着迭代而更新 // max是当前最长回文串在总字符串中所能延伸到的最右端的位置 // maxIdx是当前已知的最长回文串中心点 // maxSpan是当前已知的最长回文串向左或向右能延伸的长度 int idx = 0, max = 0; int maxIdx = 0; int maxSpan = 0; int[] p = new int[str.length()]; for(int curr = 1; curr < str.length(); curr++){ // 找出当前下标相对于idx的对称点 int symmetryOfCurr = 2 * idx - curr; // 若是当前已知延伸的最右端大于当前下标,咱们能够用对称点的P值,不然记为1等待检查 p[curr] = max > curr? Math.min(p[symmetryOfCurr], max - curr):1; // 检查并更新当前下标为中心的回文串最远延伸的长度 while((curr+p[curr])<str.length() && str.charAt(curr+p[curr])==str.charAt(curr-p[curr])){ p[curr]++; } // 检查并更新当前已知可以延伸最远的回文串信息 if(curr+p[curr]>max){ max = p[curr] + curr; idx = curr; } // 检查并更新当前已知的最长回文串信息 if(p[curr]>maxSpan){ maxSpan = p[curr]; maxIdx = curr; } } //去除占位符 return s.substring((maxIdx-maxSpan)/2,(maxSpan+maxIdx)/2-1); } private String preProcess(String s){ // 如ABC,变为$#A#B#C# StringBuilder sb = new StringBuilder(); sb.append("$"); for(int i = 0; i < s.length(); i++){ sb.append("#"); sb.append(s.charAt(i)); } sb.append("#"); return sb.toString(); } }
Q:若是只能在头或尾删,问最少删多少字符能使得该字符串变为回文?A:就是找到最长回文串,而后把长度减一下就好了。