LeetCode - 回文串问题(另附以上题目解析)
125. 验证回文串
给定一个字符串,验证它是否是回文串,只考虑字母和数字字符,可以忽略字母的大小写。
说明:本题中,我们将空字符串定义为有效的回文串。
示例 1:
输入: “A man, a plan, a canal: Panama”
输出: true
示例 2:
输入: “race a car”
输出: false
自顶向下
class Solution {
public boolean isPalindrome(String s) {
//自顶向下
//1.filter out number & char
//2. reverse and compare
String filteredS = _filterNonNumberAndChar(s);
return _reverseString(filteredS).equalsIgnoreCase(filteredS);
}
private String _reverseString(String filteredS) {
return new StringBuilder(filteredS).reverse().toString();
}
private String _filterNonNumberAndChar(String s) {
return s.replaceAll("[^A-Za-z0-9]","");
}
}
使用语言中的字符串翻转 API 得到 sgood 的逆序字符串 sgood_rev,只要这两个字符串相同,那么sgood 就是回文串。
/**
* 第一种是使用语言中的字符串翻转 API 得到 sgood 的逆序字符串 sgood_rev,只要这两个字符串相同,那么sgood 就是回文串。
* @param s
* @return
*/
/*
public boolean isPalindrome(String s) {
StringBuffer sgood = new StringBuffer();
int length = s.length();
for (int i = 0; i < length; i++) {
char ch = s.charAt(i);
if (Character.isLetterOrDigit(ch)){
sgood.append(Character.toLowerCase(ch));
}
}
StringBuffer sgood_rev = new StringBuffer(sgood).reverse();
return sgood.toString().equals(sgood_rev.toString());
}
双指针
初始时,左右指针分别指向sgood 的两侧,随后我们不断地将这两个指针相向移动,每次移动一步,并判断这两个指针指向的字符是否相同。当这两个指针相遇时,就说明sgood 时回文串。
//双指针,初始时,左右指针分别指向sgood 的两侧,随后我们不断地将这两个指针相向移动,每次移动一步,并判断这两个指针指向的字符是否相同。当这两个指针相遇时,就说明sgood 时回文串。
public boolean isPalindrome(String s) {
StringBuffer sgood = new StringBuffer();
int length = s.length();
for (int i = 0; i < length; i++) {
char ch = s.charAt(i);
if (Character.isLetterOrDigit(ch)){
sgood.append(Character.toLowerCase(ch));
}
}
int n = sgood.length();
int left = 0,right = n - 1;
while (left < right){
if (Character.toLowerCase(sgood.charAt(left)) != Character.toLowerCase(sgood.charAt(right))){
return false;
}
++left;
--right;
}
return true;
}
680. 验证回文字符串 Ⅱ
给定一个非空字符串 s,最多删除一个字符。判断是否能成为回文字符串。
示例 1:
输入: “aba”
输出: True
示例 2:
输入: “abca”
输出: True
解释: 你可以删除c字符。
贪心:
public boolean validPalindrome(String s) {
for (int i = 0,j = s.length() - 1; i < j; i++,j--) {
if (s.charAt(i) != s.charAt(j)){
//分两种情况,一是右边减一,二十左边加一
return isPalindrome(s,i,j-1) || isPalindrome(s,i+1,j);
}
}
return true;
}
private boolean isPalindrome(String s, int i, int j) {
while (i < j){
if (s.charAt(i++) != s.charAt(j--)){
return false;
}
}
return true;
}
递归,感觉下面的代码写的很漂亮,但是好像复杂度不是很好
public boolean validPalindrome(String s) {
return validPalindrome(s, 0, s.length()-1, 1);
}
/**
*
* @param s 输入字符串
* @param left 左指针
* @param right 右指针
* @param chance 删除节点的机会次数
*/
private boolean validPalindrome(String s, int left, int right, int chance) {
if (left > right) {
return true;
}
if (s.charAt(left) == s.charAt(right)) {
return validPalindrome(s, left + 1, right - 1, chance);
} else {
if (chance == 0) {
return false;
}
return validPalindrome(s, left, right - 1, chance-1) || validPalindrome(s, left + 1, right, chance-1);
}
}
5. 最长回文子串
给定一个字符串 s,找到 s 中最长的回文子串。你可以假设 s 的最大长度为 1000。
示例 1:
输入: “babad”
输出: “bab”
注意: “aba” 也是一个有效答案。
示例 2:
输入: “cbbd”
输出: “bb”
下面代码运行起来是报错的。。。
class Solution {
public static String longestPalindrome(String s) {
Map<Character, Integer> map = new HashMap<>();
Character[] arr = new Character[s.length()];
String ans = "";
for (int i = 0; i < s.length(); i++) {
char kk = s.charAt(i);
arr[i] = kk;
//System.out.println("测试······" + arr[i]);
if (map.containsKey(kk)) {//查看集合中时候包含相同的字母,有相同字母则为回文数
int count = i;//如果数组中发现相同字母,则记录第二次出现的字母的下标
for (int j = map.get(s.charAt(i)); j <= count; j++) {
//输出从一开始的字母到又重复字母的字符串
ans += String.valueOf(arr[j+1]);
break;
}
}
map.put(s.charAt(i), i);
}
ans =arr[0] + ans;
return ans;
}
}
中心扩散法
public String longestPalindrome1(String s) {
if (s == null || s.length() == 0) {
return "";
}
int strLen = s.length();
int left = 0;
int right = 0;
int len = 1;
int maxStart = 0;
int maxLen = 0;
for (int i = 0; i < strLen; i++) {
left = i - 1;
right = i + 1;
while (left >= 0 && s.charAt(left) == s.charAt(i)) {
len++;
left--;
}
while (right < strLen && s.charAt(right) == s.charAt(i)) {
len++;
right++;
}
while (left >= 0 && right < strLen && s.charAt(right) == s.charAt(left)) {
len = len + 2;
left--;
right++;
}
if (len > maxLen) {
maxLen = len;
maxStart = left;
}
len = 1;
}
return s.substring(maxStart + 1, maxStart + maxLen + 1);
}
参考链接:中心扩散法