classSolution:deflongestPalindrome(self, s:str)->str:
n =len(s)
dp =[[False]* n for _ inrange(n)]# dp[i][j]代表从索引i到索引j是否为回文
ans =""# 枚举子串的长度 l+1for l inrange(n):# 枚举子串的起始位置 i,这样可以通过 j=i+l 得到子串的结束位置for i inrange(n):
j = i + l
if j >=len(s):breakif l ==0:
dp[i][j]=Trueelif l ==1:
dp[i][j]=(s[i]== s[j])else:
dp[i][j]=(dp[i +1][j -1]and s[i]== s[j])if dp[i][j]and l +1>len(ans):
ans = s[i:j+1]return ans
'''
动态规划的思想,第一维是起始索引i,第二维是结束索引j (约定j>i)
转移方程dp[i][j] = dp[i+1][j-1] and (s[i]==s[j])
而最外层循环怎么开始呢,这是一个比较难想到的点。
显然从最小的长度开始。最外层循环的值是当前检索字串的长度。
长度逐渐增加,知道字串长度==len(s),动态规划的遍历便完成了。
'''# 在状态转移方程中,我们是从长度较短的字符串向长度较长的字符串进行转移的,因此一定要注意动态规划的循环顺序。# 从中心向两边生长的方法classSolution:defexpandAroundCenter(self,s,left, right):while left>=0and right<len(s)and s[left]== s[right]:
left -=1
right +=1return left+1, right-1# python可以方便的返回多个参数,而不用 封装,这种方法用Java实现的话,如果返回长度,则还需要进行一些运算deflongestPalindrome(self, s:str)->str:
start, end =0,0for i inrange(len(s)):
left1, right1 = self.expandAroundCenter(s,i,i)
left2, right2 = self.expandAroundCenter(s,i,i+1)if(right1-left1>end-start):
start, end = left1, right1
if(right2-left2 > end - start):
start, end = left2,right2
return s[start:end+1]
6 Z字变换
python
classSolution:defconvert(self, s:str, numRows:int)->str:if numRows <2:return s
res =[""for _ inrange(numRows)]
i, flag =0,-1for c in s:
res[i]+= c
if i ==0or i == numRows -1: flag =-flag
i += flag
return"".join(res)
java
classSolution{
public String convert(String s,int numRows){
if(numRows==1)return s;
StringBuilder[] ss =newStringBuilder[numRows];for(int i=0;i<numRows;i++) ss[i]=newStringBuilder();boolean dir =true;int index =0;for(int i=0;i<s.length();i++){
ss[index].append(s.charAt(i));if(index==0&& dir==false) dir =!dir;if(index==numRows-1&& dir ==true) dir =!dir;if(dir){
index++;}else{
index--;}}
StringBuilder res =newStringBuilder();for(StringBuilder sb : ss){
res.append(sb);}return res.toString();}}