字符串类算法题---回文串、同构字符串、回文数、计数二进制子串

1.最长回文串

力扣传送门

    /*
    * 计算一组字符集合可以组成的回文字符串的最大长度
    * */
    public int longestPalindrome(String s) {
        if (s == null || s.length() == 0) return 0;
        int sMap[] = new int[128];
        for (int i = 0; i < s.length(); i++) {
            sMap[s.charAt(i)]++;
        }
        int tmp = 0;
        int count = 0;
        for (int i = 0; i < sMap.length; i++) {
            if (sMap[i] % 2 == 1) tmp = 1;
            count += sMap[i] / 2;
        }
        return count * 2 + tmp;
    }

    @Test
    public void test() {
        System.out.println(longestPalindrome("abccccdd"));
    }

2.同构字符串

力扣传送门

 /*
    * 同构字符串
    * 给定两个字符串 s 和 t,判断它们是否是同构的。如果 s 中的字符可以被替换得到 t ,那么这两个字符串是同构的。
    * 所有出现的字符都必须用另一个字符替换,同时保留字符的顺序。两个字符不能映射到同一个字符上,但字符可以映射自己本身。
    * */
    public boolean isIsomorphic(String s, String t) {//做法一
        if (s == null || t == null || s.length() != t.length()) return false;
        Map st = new HashMap<>();
        Map ts = new HashMap<>();
        int len = s.length();
        for (int i = 0; i < len; i++) {
            if (st.containsKey(s.charAt(i))) {
                if (st.get(s.charAt(i)) != t.charAt(i)) return false;
            } else if (ts.containsKey(t.charAt(i))) {
                if (ts.get(t.charAt(i)) != s.charAt(i)) return false;
            } else {
                st.put(s.charAt(i), t.charAt(i));
                ts.put(t.charAt(i), s.charAt(i));
            }
        }
        return true;
    }

    public boolean isIsomorphic2(String s, String t) {//做法二
        return isIsomorphicHelper(s, t) && isIsomorphicHelper(t, s);
    }

    public boolean isIsomorphicHelper(String str1, String str2) {//验证str1可以被唯一的映射到str2
        HashMap map = new HashMap<>();//s->t
        for (int i = 0; i < str1.length(); i++) {
            char c1 = str1.charAt(i);
            char c2 = str2.charAt(i);
            if (map.containsKey(c1)) {
                if (map.get(c1) != c2) {
                    return false;
                }
            } else {
                map.put(c1, c2);
            }
        }
        return true;
    }

3.回文子串的个数

力扣传送门

/*
    * 回文子字符串个数
    * 给定一个字符串,你的任务是计算这个字符串中有多少个回文子串。具有不同开始位置或结束位置的子串,即使是由相同的字符组成,也会被计为是不同的子串。
    * */
    //回文子串的个数
    public int countSubstrings(String s) {
        if (s == null || s.length() == 0) return 0;
        int n = s.length();
        boolean dp[][] = new boolean[n][n];//dp[i][j]表示i~j之间是否为回文串
        int count = 0;
        for (int len = 0; len < n; len++) {
            for (int i = 0; i < n - len; i++) {
                int j = i + len;
                if (s.charAt(i) == s.charAt(j) && (j - i <= 1)) {
                    dp[i][j] = true;
                    count++;
                } else if (s.charAt(i) == s.charAt(j) && dp[i + 1][j - 1]) {
                    dp[i][j] = true;
                    count++;
                }
            }
        }
        return count;
    }

4.回文数判断

力扣传送门
判断一个整数是否是回文数。回文数是指正序(从左向右)和倒序(从右向左)读都是一样的整数。

    /*
    * 回文数
    * 判断一个整数是否是回文数。回文数是指正序(从左向右)和倒序(从右向左)读都是一样的整数。
    * 要求:不将整数转为字符串
    * 思路:例如,输入 1221,我们可以将数字 “1221” 的后半部分从 “21” 反转为 “12”,并将其与前半部分 “12” 进行比较,因为二者相同,我们得知数字 1221 是回文。
    *  要注意10这种情况
    * */
    public boolean isPalindrome(int x) {
        if (x < 0) return false;//负数直接返回false
        if (x == 0) return true;//是0返回true
        if (x % 10 == 0) return false;//注意这个条件。因为后面判断x == x2 / 10时,会把10,110错误返回为true
        int x2 = 0;
        while (x > x2) {
            int num = x % 10;
            x = x / 10;
            x2 = x2 * 10 + num;
        }
        return x == x2 || x == x2 / 10;
    }

    @Test
    public void test2() {
        System.out.println(isPalindrome(110));
    }

5.计数二进制子串

力扣传送门
统计二进制字符串中连续 1 和连续 0 数量相同的子字符串个数

 /*
    * 计数二进制子串:统计二进制字符串中连续 1 和连续 0 数量相同的子字符串个数
    * 给定一个字符串 s,计算具有相同数量0和1的非空(连续)子字符串的数量,并且这些子字符串中的所有0和所有1都是组合在一起的。重复出现的子串要计算它们出现的次数。
    * */
    public int countBinarySubstrings(String s) {//方法一:动态规划O(N^2)超时
        if (s == null || s.length() == 0) return 0;
        int n = s.length();
        int count = 0;
        boolean dp[][] = new boolean[n + 1][n + 1];//i~j之间是否为 符合条件的子串
        for (int j = 0; j < n; j++) {
            for (int i = j - 1; i >= 0; i--) {
                if (s.charAt(i) != s.charAt(j)) {
                    if ((j - i == 1) || (dp[i + 1][j - 1] && s.charAt(i) == s.charAt(i + 1) && s.charAt(j) == s.charAt(j - 1))) {
                        dp[i][j] = true;
                        count++;
                    }
                }
            }
        }
        return count;
    }

    public int countBinarySubstrings2(String s) {//方法一:先分块,连续的1或0被分到一块,再统计 O(N)
        if (s == null || s.length() == 0) return 0;
        int batch[] = new int[s.length()];
        int count = 0;
        batch[count] = 1;
        for (int i = 1; i < s.length(); i++) {
            if (s.charAt(i) == s.charAt(i - 1)) {
                batch[count]++;
            } else {
                count++;
                batch[count] = 1;
            }
        }
        int cnt = 0;
        for (int i = 0; i < count; i++) {
            cnt += Math.min(batch[i], batch[i + 1]);
        }
        return cnt;
    }

    @Test
    public void test3() {
        System.out.println(countBinarySubstrings2("10101"));
    }

你可能感兴趣的:(数据结构与算法,经典面试题)