leetcode 回文问题小结
1.Palindrome Number
- 问题描述
判断数字是否是回文,空间复杂度O(1)。 - 解题思路
法一: 将数字转换成字符串,判断一个字符串是否是回文。
public boolean isPalindrome(int x) {
if(x < 0)
return false;
if(x == 0)
return true;
if(x/10==0)
return true;
String str = x + "";
int i = 0;
while(i < str.length()/2){
if(str.charAt(i)!=str.charAt(str.length()-1-i))
return false;
i++;
}
return true;
}
法二:获得reverse之后的数字,如果两个数字相同,则是回文。
public boolean isPalindrome(int x) {
if(x < 0)
return false;
if(x == 0)
return true;
if(x/10==0)
return true;
int pre = x;
int ret = 0;
while(x != 0){
ret = ret * 10 + x%10;
x /= 10;
}
return ret==pre ? true : false;
}
2.Palindrome Linked List
- 问题描述
判断单链表是不是回文,时间复杂度O(n),空间复杂度O(1)。 - 解题思路
将链表前一半反转,中间值为头指针,头变成尾,如果与后半部分相同,就是回文链表,会破坏链表结构。改进:用快慢指针求链表中点。
public boolean isPalindrome(ListNode head) {
if(head == null || head.next ==null)
return true;
int length = getLength(head);
int leftEnd = length/2;
ListNode pre = null;
for(int k = 0; k < leftEnd; k++){
ListNode var = head.next;
head.next = pre;
pre = head;
head = var;
}
if(length%2!=0)
head = head.next;
while(pre != null && head != null){
System.out.println(pre.val+":"+head.val);
if(pre.val != head.val){
return false;
}
pre = pre.next;
head = head.next;
}
return (pre == null && head == null) ? true : false;
}
public int getLength(ListNode head){
int count = 0;
while(head!=null){
count++;
head = head.next;
}
return count;
}
3.Shortest Palindrome
- 问题描述
给定一个字符串S,你可以通过在它前面添加字符将它转换为回文。 查找并返回通过执行此转换可以找到的最短回文。 - 解题思路
找到S中以字符串首位为开头的最长回文,将剩余部分反序后添加到S的头部。查找最长回文时,从中间向两边查找。
public String shortestPalindrome(String s) {
if(s.length()==0 ||s.length()==1)
return s;
String ret = "";
int center = (s.length()-1)/2;
for(int j = center; j>=0;j--){
if(s.charAt(j) == s.charAt(j+1))
if((ret = isPalindrome(s,j,j+1))!=null)
break;
if((ret = isPalindrome(s,j,j))!=null)
break;
}
return ret+s;
}
public String isPalindrome(String s,int left,int right) {
int i = 0;
for(; left-i>=0 && right+i<s.length();i++){
if(s.charAt(left-i) != s.charAt(right+i))
break;
}
if((left-i)>=0)
return null;
StringBuffer sb = new StringBuffer(s.substring(right+i));
return sb.reverse().toString();
}
4.Palindrome Partitioning
- 问题描述
给定一个字符串s,分割s使得分割的每个子字符串是一个回文。返回s的所有可能的回文分割。 - 解题思路
递归方法
List<List<String>> listAll = new ArrayList<>();
public List<List<String>> partition(String s) {
if(s == null || s.length() == 0)
return listAll;
List<String> var = new ArrayList<>();
if(s.length() == 1){
var.add(s);
listAll.add(var);
return listAll;
}else{
getPartition(s,var);
}
return listAll;
}
public void getPartition(String s, List<String> list){
if(s.length() == 0)
listAll.add(list);
if(s.length() == 1){
list.add(s);
listAll.add(list);
return;
}
int n = s.length();
for(int i = 1; i <= n; i++){
String str = s.substring(0,i);
if(isPalindrome(str)){
List<String> varList = new ArrayList<>();
if(list.size() != 0){
for(String varStr : list){
varList.add(varStr);
}
}
varList.add(str);
getPartition( s.substring(i,n),varList);
}
}
}
public boolean isPalindrome(String s){
if(s.length() == 1){
return true;
}
int i = 0, j = s.length() - 1;
while(i <= j){
if(s.charAt(i) != s.charAt(j))
return false;
i++;
j--;
}
return true;
}
优化后:
List<List<String>> resultLst;
ArrayList<String> currLst;
public List<List<String>> partition(String s) {
resultLst = new ArrayList<List<String>>();
currLst = new ArrayList<String>();
backTrack(s,0);
return resultLst;
}
public void backTrack(String s, int l){
if(currLst.size()>0 //the initial str could be palindrome
&& l>=s.length()){
List<String> r = (ArrayList<String>) currLst.clone();
resultLst.add(r);
}
for(int i=l;i<s.length();i++){
if(isPalindrome(s,l,i)){
if(l==i)
currLst.add(Character.toString(s.charAt(i)));
else
currLst.add(s.substring(l,i+1));
backTrack(s,i+1);
currLst.remove(currLst.size()-1);
}
}
}
public boolean isPalindrome(String str, int l, int r){
if(l==r) return true;
while(l<r){
if(str.charAt(l)!=str.charAt(r)) return false;
l++;r--;
}
return true;
}
5.Valid Palindrome
- 问题描述
给定一个字符串,确定它是否是回文的,仅仅考虑其中的数字和字符并忽略其他。
例如,
“A man, a plan, a canal: Pannama” 是回文的。
“race a car” 不是回文。 - 解题思路
定义空字符串是回文,将首位空格去掉,使用两个指针,头指针和尾指针,指向空格时跳过。
public boolean isPalindrome(String s) {
if(s.length()<=1)
return true;
int i = 0, j = s.length() - 1;
while(i <= j){
while(i<=j && !isAlNum(s.charAt(i))) i++;
while(i<=j && !isAlNum(s.charAt(j))) j--;
if(i <= j){
String str1 = s.charAt(i)+"";
String str2 = s.charAt(j)+"";
if(str1.compareToIgnoreCase(str2)!=0)
return false;
}
i++;
j--;
}
return true;
}
public boolean isAlNum(char ch){
int asc = (int)ch;
if((asc >= 48 && asc <= 57) || (asc >= 65 && asc <= 90) || (asc >= 97 && asc <= 122))
return true;
return false;
}
法二:先将字符串的空格去掉,都变成小写格式
public boolean isPalindrome(String s) {
if(s == null)
return false;
s = s.replaceAll("[^a-zA-Z0-9]", "").toLowerCase();
if(s.length()<=1)
return true;
int i = 0, j = s.length() - 1;
while(i <= j){
if(s.charAt(i) != s.charAt(j))
return false;
i++;
j--;
}
return true;
}
6.Longest Palindrome
- 问题描述
给定一个由小写或大写字母组成的字符串,找到可以用这些字母构建的最长回文的长度。区分大小写,Aa不是 - 解题思路
字母出现偶数次的都可以加到回文中。奇数次的要-1。
public int longestPalindrome(String s) {
if(s == null)
return 0;
if(s.length()<=1)
return s.length();
HashMap<Character,Integer> map = new HashMap<>();
int sum = 0;
boolean flag = false;
for(int i = 0; i < s.length(); i++){
if(map.containsKey(s.charAt(i))){
map.put(s.charAt(i),map.get(s.charAt(i))+1);
}else{
map.put(s.charAt(i),1);
}
}
for(Integer value : map.values()){
if(value%2 == 0)
sum += value;
else{
flag = true;
sum += value - 1;
}
}
return flag ? sum + 1 : sum;
}
7.Longest Palindromic Substring
- 问题描述
给定一个字符串s,在s中找到最长的回文子串。 您可以假设s的最大长度为1000。 如 “babad” 的输出是 “bab”或者“aba” - 解题思路
暴力求解:穷举思路:取出所有的子串,判断它是否回文,并返回最长的子串。
动态规划:用boolean[i][j]=true 表示字符串从i到j的子串是回文串,当 pali[i+1][j-1] == true && s.charAt(i)==s.charAt(j)时,pali[i][j] = true;否则为false
空间、时间复杂度 O(n2)
public String longestPalindrome(String s) {
//时间o(n2) 空间o(n2) 动态规划
if(s.length()==0 || s.length()==1)
return s;
int max = 0;
String ret = "";
boolean pali[][] = new boolean[s.length()][s.length()];
for(int i = 0; i < s.length(); i++){
for(int j = 0; j < s.length(); j++){
pali[i][j] = false;
}
}
for(int i = 0; i < s.length(); i++){
pali[i][i] = true;
if(i < (s.length()-1)){
if(s.charAt(i)==s.charAt(i+1))
pali[i][i+1] = true;
else{
pali[i][i+1] = false;
}
}
}
for(int i = s.length()-1; i >= 0; i--){
for(int j = s.length()-1; j >= i; j--){
if(pali[i][j] == true){
if(max < (j - i + 1)){
max = j - i + 1;
ret = s.substring(i,j+1);
}
continue;
}
if((j - i) ==1)
continue;
if( pali[i+1][j-1] == true && s.charAt(i)==s.charAt(j)){
pali[i][j] = true;
if(max < (j - i + 1)){
max = j - i + 1;
ret = s.substring(i,j+1);
}
}
else
pali[i][j] = false;
}
}
return ret;
}
Manacher算法: