Given a string s, find the longest palindromic substring in s. You may assume that the maximum length of s is 1000.
Example 1:
Input: "babad"
Output: "bab"
Note: "aba" is also a valid answer.
Example 2:
Input: "cbbd" Output: "bb"
这个博客说的很好,很优秀,解法全面,有空应该看下
https://www.cnblogs.com/grandyang/p/4464476.html
解法:
主要需要注意的就是:一般根据左右计算距离的时候,不要被左右这个字眼迷惑,真正理解在实际中的位置含义,尤其是这种左右变量本身也在
循环中迭代,数值不断变化,有可能出问题
2plus:
when look tutorial,attention to < <= whether have = important than number.
Maybe make some change to make sure some variable change,please remeber to change it back
BONUS:
left right is just a represent for calculation.Pay attention to its real meaning.If it's really
the left and right.if it need +-1 to represent the real meaning
Be good at using &
when we want to let a function change variable value instead of global variable use & to change it
is a good choice
#include <iostream> #include <algorithm> #include<string> using namespace std; class Solution { public: string longestPalindorme(string s) { if(s.size()<2) return s; int n=s.size(),maxLen=0,start=0; //ATTENTION:this range should be n-1,because this is i+1 at below,if <n out of range,if want from 1->n need i-1,i this combination for(int i=0;i<n-1;++i)i-1 { //为了对比奇数和偶数回文 SearchPalindorm(s,i,i,start,maxLen); SearchPalindorm(s,i,i+1,start,maxLen); } cout<<"start:"<<start<<"maxLen:"<<maxLen<<endl; return s.substr(start,maxLen); } void SearchPalindorm(string s,int left,int right,int& start,int& maxLen) { while(left>=0&&right<s.size()&&s[left]==s[right]) { --left; ++right; } //这里真的很反套路:本身看到left和right都能意识到right-left+1才是长度,但这里只有当left和right不符合情况的时候才会退出循环,即此时的left和right都是被多加和间了一次的,所以真实情况是(right-1)-(left+1)+1最后拆开就是下面的情况 if(maxLen<right-left-1) { start=left+1; maxLen=right-left-1; } } }; int main() { Solution s; string si,so; //cin>>si; si="abbad"; so=s.longestPalindorme(si); cout<<so<<endl; return 0; }
Change the above-mentioned method,use Pruning operation save time use jump duplicate character divide operate odd and even situation.very quick and save space method.show as below:
#include<iostream> #include<string> #include<stdio.h> #include<string.h> #include<iomanip> #include<vector> #include<list> #include<queue> #include<algorithm> #include<stack> #include<map> using namespace std; class Solution { public: string longestPalindrome(string s) { //special case if(s.size()<2) return s; //stop early&jump duplicate int n=s.size(),maxLen=0,start=0; for(int i=0;i<n;) { //Pruning operation make code faster if(n-i<maxLen/2) break; int left=i,right=i; //solve odd and even if even jump its duplicate center while(right<n-1&&s[right]==s[right+1]) { right++; } //replace i++'s function i=right+1; //ATTENTION:use left-1&right+1 compare if equal then execute operation,guarantee variable represent actual value while(left-1>=0&&right+1<n&&s[left-1]==s[right+1]) { left--; right++; } if(right-left+1>maxLen) { maxLen=right-left+1; start=left; } } //function has different usage in different language,in C++ substr means start and length return s.substr(start,maxLen); } }; int main() { Solution s1; cout<<s1.longestPalindrome("an0naw")<<endl; return 0; }
After such a long term finally get in charge of this function Manacher:
this is the method I solved by myself,At first,it appear a problem is index calculate error,so just an example can make it clear
class Solution(object): def longestPalindrome(self, s): """ :type s: str :rtype: str """ # preaction s="#"+"#".join(s)+"#" # print(s) # initialization maxR=0 maxL=0 pos=0 poss=0 p=[0]*len(s) # for loop initial p for i in range(len(s)): p[i]=min(p[int(pos*2-i)],maxR-i) if i<maxR else 1 while i+p[i]<len(s) and i-p[i]>=0 and s[i+p[i]]==s[i-p[i]]: p[i]+=1 if maxR<i+p[i]: maxR=i+p[i] pos=i if maxL<p[i]: maxL=p[i] poss=i # print(maxL) # print(poss) # s_res="" s_res=s[poss-maxL+1:poss+maxL-1] return s_res.replace("#","") # print("fa") # print(s_res) # print("fb") # print(s_res.replace("#","")) solu=Solution() print(solu.longestPalindrome(s="annaw"))
311908update structure has progess
late problem be solved:
i+p[i] i-p[i] needn't -1 +1 because if p[i]==1 it will count i twice to compare it with i itself
directly plus and minus won't have this problem
class Solution(object): def longestPalindrome(self, s): """ :type s: str :rtype: str """ # preaction s='#'+'#'.join(s)+'#' # print(s) # initial MaxR=0 MaxL=0 pos=0 ppos=0 p=[0]*len(s) # judge for i in range(len(s)): p[i]=min(MaxR-i,p[2*pos-i]) if i<MaxR else 1 # addition analyse while i+p[i]<len(s) and i-p[i]>=0 and s[i+p[i]]==s[i-p[i]]: p[i]+=1 # update if MaxR<i+p[i]: MaxR=i+p[i] pos=i if MaxL<p[i]: MaxL=p[i] poss=i p_res=s[poss-MaxL+1:poss+MaxL-1] return p_res.replace('#','')
C++ version:
in C++ solution,need add extra character before string,because C++ don't have replace function like python,so the answer cannot show as changed string but original string.So it need to find corresponding relationship between orginal and replaced one
ATTENTION point:
C++/Python cannot directly plus character to string array,so new a new string is very important.But python has function join can directly use "#".join(s) add "#" between string.
use new name such as nfinal easy to miss with n,maybe cause error.
#include<iostream> #include<string> using namespace std; class Solution { public: string longestPalindrome(string s) { //pre-action int n=s.size(); string trans="$#"; for(int i=0;i<n;i++) { trans+=s[i]; trans+="#"; } int nfinal=trans.size(); //initialize int MaxR=0;int posR=0; int MaxL=0;int posRes=0; int len[nfinal]={0}; //judge for(int i=0;i<nfinal;i++) { len[i]=i<MaxR?min(len[2*posR-i],MaxR-i):1; while(i+len[i]<nfinal&&i-len[i]>=0&&trans[i+len[i]]==trans[i-len[i]]) { len[i]++; } //compare if(len[i]>MaxL) { MaxL=len[i]; posRes=i; } if(i+len[i]>MaxR) { MaxR=len[i]+i; posR=i; } } //deal result //cout<<"p"<<posRes<<"M"<<MaxL<<endl; return s.substr((posRes-MaxL)/2,MaxL-1); } }; int main() { Solution s1; string s="annaw"; cout<<s1.longestPalindrome(s)<<endl; return 0; }
DP method use array to store flag whether j to i(j<i) is a palindrome string,use recursion formula.
But time and space just only 3,40% opponents were defeated.
code please remeber to initialize len as 1,or it will cause problem when example like {ac} this not duplicate example
ALSO don't forget DEALSPECIAL CASE!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
#include<iostream> #include<string> #include<stdio.h> #include<string.h> #include<iomanip> #include<vector> #include<list> #include<queue> #include<algorithm> #include<stack> #include<map> using namespace std; class Solution { public: string longestPalindrome(string s) { //special case operation don't forget if(s.empty()) return ""; if(s.size()==1) return s; //array method int n=s.size(); //must initialize to 1,on one way there must minimum this value would be 1,on the other,if example like ac this not have duplicate number while not operate calculation int arr[n][n]={0},left=0,len=1; for(int i=0;i<n;i++) { arr[i][i]=1; for(int j=0;j<i;j++) { arr[j][i]=((s[i]==s[j])&&(i-j<2||arr[j+1][i-1])); if(arr[j][i]&&(i-j+1>len)) { len=i-j+1; left=j; } } } return s.substr(left,len); } }; int main() { Solution s1; cout<<s1.longestPalindrome("ac")<<endl; return 0; }
6. ZigZag Conversion
The string "PAYPALISHIRING"
is written in a zigzag pattern on a given number of rows like this: (you may want to display this pattern in a fixed font for better legibility)
P A H N
A P L S I I G
Y I R
And then read line by line: "PAHNAPLSIIGYIR"
Write the code that will take a string and make this conversion given a number of rows:
string convert(string s, int numRows);
Example 1:
Input: s = "PAYPALISHIRING", numRows = 3
Output: "PAHNAPLSIIGYIR"
Example 2:
Input: s = "PAYPALISHIRING", numRows = 4
Output: "PINALSIGYAHRPI"
Explanation:
P I N
A L S I G
Y A H R
P I
#coding=utf-8 class Solution(object): def convert(self, s, numRows): """ :type s: str :type numRows: int :rtype: str """ length = len(s) #总共有多少元素 step = 2*numRows-2 #有几列, 2n-2 = 0+(n-1)+(n-2)+1 if s == "": #如果空字符串,返回空字符串"" return "" if length<numRows or numRows ==1 : #如果只有一行,则直接返回原字符串 return s result = s[::step] #这是第一行,他通过切片的步进step来取值,因为每个元素都是间隔一个step #这题里面,首行和尾行是特殊的,所以要区别对待 for i in range(1,numRows-1): #开始迭代除了第一行和最后一行之外的中间所有行 for j in range(i,length,step): #这里关键的地方,他将图形在纵向上进行切割,以每个step为标准开头,进行迭代 result += s[j] #在每次切割后,进行添加的第一个元素,应该是每一行的开头的元素加上某倍数的step if j+(step-i*2) < length: #如果斜线上的元素是在总长度以内的 result += s[j+step-i*2] #那么,就添加此元素 result += s[numRows-1::step] #最后一行开始迭代 print (result) return result
C++ version:
Special case always need to be handle firstly to inprove performance
#include<bits/std++.h> #include<vector> #include<string> #include<string.h> using namespace std; class Solution { public: string convert(string s, int numRows) {
//easy forget
if(numRows==1) return s;
vector<string> ss(numRows); int n=s.length(); int i=0,f=0; bool down=true; while(i<n) { // if(down) { ss[f]+=s[i]; f++; if(f==numRows) { f-=2; down=false; } } else { ss[f]+=s[i]; f--; if(f==-1) { f=1; down=true; } } i++; } string ans; for(auto t:ss) { ans+=t; } return ans; } }; int main() { Solution s1; string s="PAYPALISHIRING"; int numRows=3; string ans; ans=s1.convert(s,numRows); cout<<ans<<endl; string res="PINALSIGYAHRPI"; return 0; }