leetcode - [125] 验证回文串|刷题打卡

446 阅读2分钟

leetcode - [125] 验证回文串|刷题打卡

​ 我是通过idea的leetcode插件获取题目做题的,所以题目描述基本都会有注释符号哈

1. 题目描述

 * // [125] 验证回文串
 * // 给定一个字符串,验证它是否是回文串,只考虑字母和数字字符,可以忽略字母的大小写。
 * //
 * // 说明:本题中,我们将空字符串定义为有效的回文串。
 * //
 * // 示例 1:
 * //
 * // 输入: "A man, a plan, a canal: Panama"
 * //输出: true
 * //
 * //
 * // 示例 2:
 * //
 * // 输入: "race a car"
 * //输出: false
 * //
 * // Related Topics 双指针 字符串

2. 思路分析

​ 这道题目看到跟之前的[9] 回文数类似,使用 双指针 ,对照前后,如果全部符合,返回true,中间有不匹配的,返回false

​ 区别主要在于可能存在 非数字、非字母的内容需要跳过,主要在于这部分的实现。

​ 下面的代码用了两种方式:

1. Character.isLetterOrDigit() 方法(PS:这个方法会将中文也当成字母,即Letter)
2. 手动实现

3. AC代码

public class No125 {
    public boolean isPalindrome(String s) {
        return method1(s);
//        return method2(s);
    }

    /**
     * 解析为小写字符数组
     * 调用 JDK Character 自带 isLetterOrDigit方法来判断是否落在 字母和数字范围(注意:isLetterOrDigit 会把中文当成是字符)
     *
     * @param s
     * @return
     */
    private boolean method1(String s) {
        s = s.toLowerCase();
        char[] c = s.toCharArray();
        int l = 0;
        int r = s.length()-1;
        // 左边的指针还小于右边的就继续进行校验判断,会慢慢往中间靠近
        while(l < r) {
            if(!isLetterOrDigit(c[l])) {
                l++;
            } else if(!isLetterOrDigit(c[r])) {
                r--;
            } else if(c[l++] != c[r--]) {
                return false;
            }
        }
        return true;
    }

    /**
     * Character的方法,copy过来了
     * 这方面还不是特别懂,我理解是把 对应 Letter 和数字范围的字符 取并集
     *
     * 相关链接:https://www.compart.com/en/unicode/category
     * @param codePoint
     * @return
     */
    public static boolean isLetterOrDigit(int codePoint) {
        return (
            (
                (
                    // 赋值 对应Letter 的值,取并集
                    (1 << Character.UPPERCASE_LETTER) |
                      (1 << Character.LOWERCASE_LETTER) |
                      (1 << Character.TITLECASE_LETTER) |
                      (1 << Character.MODIFIER_LETTER) |
                      (1 << Character.OTHER_LETTER) |
                      (1 << Character.DECIMAL_DIGIT_NUMBER)
                    // 跟对应字符的
                ) >> Character.getType(codePoint)
            ) & 1 ) != 0;
    }

    /**
     * 来自 leetCode 解答 [手写版本无函数调用]
     *
     * 主要是封装了两个方法, isOK 和 equal
     * isOK - 字符落在字母以及数字范围内
     * equal - 忽略大小写
     *
     * 执行耗时:3 ms,击败了92.60% 的Java用户
     * 内存消耗:38.5 MB,击败了70.62% 的Java用户
     *
     * @param s
     * @return
     */
    public boolean method2(String s) {
        int i=0,j=s.length()-1;
        while(i<j){
            char a=s.charAt(i),b=s.charAt(j);
            if(isOK(a)&&isOK(b)&&!equal(a,b))return false;
            if(!isOK(a)&&i<j){i++;continue;}
            if(!isOK(b)&&i<j){j--;continue;}
            if(equal(a,b)&&i<j){i++;j--;continue;}
            if(!equal(a,b)&&i<j)return false;
            i++;j--;
        }
        return i>=j;
    }

    /**
     * 忽略大小写的限制
     *
     * @param a
     * @param b
     * @return
     */
    public boolean equal(char a,char b){
        if('a'<=a&&a<='z')a-='a';
        if('A'<=a&&a<='Z')a-='A';
        if('a'<=b&&b<='z')b-='a';
        if('A'<=b&&b<='Z')b-='A';
        return a==b;
    }

    /**
     * 字母或者数字
     *
     * @param c
     * @return
     */
    public boolean isOK(char c){
        return ('a'<=c&&c<='z')||('A'<=c&&c<='Z')||('0'<=c&&c<='9');
    }
}

4. 总结

​ 一点点感想,无论是做题还是做项目,实现功能的时候经常会需要很多工具类的帮助,以至于经常会自己封装很多工具类。其实可能很多功能都在引入的依赖中可能就包含了,或者JDK自带了,可以稍微留意一下,避免代码重复,保持代码整洁。


​ 本文正在参与「掘金 2021 春招闯关活动」, 点击查看 活动详情