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);

    }

参考链接:中心扩散法

posted @ 2020-12-18 21:12  your_棒棒糖  阅读(75)  评论(0)    收藏  举报