Leetcode 题解 - 字符串

458 阅读2分钟

1. 字符串循环移位包含

[编程之美 3.1](www.cyc2018.xyz/算法/Leetcode 题解/Leetcode 题解 - 字符串.html#)

s1 = AABCD, s2 = CDAA
Return : true

给定两个字符串 s1 和 s2,要求判定 s2 是否能够被 s1 做循环移位得到的字符串包含。

s1 进行循环移位的结果是 s1s1 的子字符串,因此只要判断 s2 是否是 s1s1 的子字符串即可。


2. 字符串循环移位

[编程之美 2.17](www.cyc2018.xyz/算法/Leetcode 题解/Leetcode 题解 - 字符串.html#)

s = "abcd123" k = 3
Return "123abcd"

将字符串向右循环移动 k 位。

将 abcd123 中的 abcd 和 123 单独翻转,得到 dcba321,然后对整个字符串进行翻转,得到 123abcd。


3. 字符串中单词的翻转

[程序员代码面试指南](www.cyc2018.xyz/算法/Leetcode 题解/Leetcode 题解 - 字符串.html#)

s = "I am a student"
Return "student a am I"

将每个单词翻转,然后将整个字符串翻转


4. 有效的字母异位词

Leetcode (opens new window)/ 力扣

可以用 HashMap 来映射字符与出现次数,然后比较两个字符串出现的字符数量是否相同。

由于本题的字符串只包含 26 个小写字符,因此可以使用长度为 26 的整型数组对字符串出现的字符进行统计,不再使用 HashMap

class Solution {
    // 哈希表
    public boolean isAnagram(String s, String t) {
        if (s.length() != t.length()) {
            return false;
        }
        int[] table = new int[26];

        for (int i = 0; i < s.length(); i++) {
            char ch = s.charAt(i);
            table[ch - 'a']++;
        }

        for (int i = 0; i < t.length(); i++) {
            char ch = t.charAt(i);

            if (--table[ch - 'a'] < 0) {
                return false;
            }
        }

        return true;
    }
}


5. 最长回文串

Leetcode (opens new window)/ 力扣

class Solution {
    public int longestPalindrome(String s) {
        int[] counts = new int[128];

        for (char ch : s.toCharArray()) {
            counts[ch]++;
        }

        int result = 0;
        for (int count : counts) {
            result += count / 2 * 2;
            
            if (result % 2 == 0 && count % 2 == 1) {
                result++;
            }
        }

        return result;
    }
}


6. 同构字符串

Leetcode (opens new window)/ 力扣

参考题解

解法 1

class Solution {
    // 哈希表
    public boolean isIsomorphic(String s, String t) {
        // 比较两次,例如 ab 和 cc,从 cc 映射到 ab 不成立
        return isMapping(s, t) && isMapping(t, s);
    }

    public boolean isMapping(String s, String t) {
        Map<Character, Character> map = new HashMap<>();

        for (int i = 0; i < s.length(); i++) {
            char ch1 = s.charAt(i);
            char ch2 = t.charAt(i);

            if (map.containsKey(ch1) == true) {
                if (map.get(ch1) != ch2) {
                    return false;
                }
            } else {
                map.put(ch1, ch2);
            }
        }

        return true;
    }
}

解法 2

class Solution {
    public boolean isIsomorphic(String s, String t) {
        int[] map1 = new int[128];
        int[] map2 = new int[128];

        for (int i = 0; i < s.length(); i++) {
            char ch1 = s.charAt(i);
            char ch2 = t.charAt(i);

            if (map1[ch1] != map2[ch2]) {
                return false;
            } else {
                if (map1[ch1] == 0) {
                    map1[ch1] = i + 1;
                    map2[ch2] = i + 1;
                }
            }
        }

        return true;
    }
}


7. 回文字串 *

Leetcode (opens new window)/ 力扣

参考题解

class Solution {
    public int countSubstrings(String s) {
        boolean[][] dp = new boolean[s.length()][s.length()];
        int result = 0;

        for (int i = 0; i < s.length(); i++) {
            for (int j = 0; j <= i; j++) {
                if (s.charAt(i) == s.charAt(j) && (i - j < 2 || dp[j + 1][i - 1])) {
                    dp[j][i] = true;
                    result++;
                }
            }
        }

        return result;
                
    }
}


8. 判断一个整数是否是回文数

转换成字符串后进行判断

class Solution {
    public boolean isPalindrome(int x) {
        String str = String.valueOf(x);
        int i = 0;
        int j = str.length() - 1;

        while (i < j) {
            if (str.charAt(i) != str.charAt(j)) {
                return false;
            }
            i++;
            j--;
        }
        
        return true;
    }
}

进阶:不转换成字符串进行判断

要求不能使用额外空间,也就不能将整数转换为字符串进行判断。

将整数分成左右两部分,右边那部分需要转置,然后判断这两部分是否相等。

class Solution {
    public boolean isPalindrome(int x) {
        // 2 种情况直接返回 false
        // 1 负数
        // 2 尾数为 0,而且不等于 0,因为 0 不可能是最高位
        if (x < 0 || (x % 10 == 0 && x != 0)) {
            return false;
        }

        // 反转后半部分进行比较
        int reverse = 0;

        while (x > reverse) {
            reverse = reverse * 10 + x % 10;
            x /= 10;
        }

        return x == reverse || x == reverse / 10;
    }
}


9. 计算二进制字串

Leetcode (opens new window)/ 力扣

class Solution {
    public int countBinarySubstrings(String s) {
        List<Integer> counts = new ArrayList<>();
        int n = s.length();
        int p = 0;

        // 将 0,1 转换成数字(个数)存储到集合中
        while (p < n) {
            char ch = s.charAt(p);
            int count = 0;

            while (p < n && s.charAt(p) == ch) {
                count++;
                p++;
            }
            counts.add(count);
        }

        // 进行遍历,求出所有的字串
        // 比较相邻,求出两个的最小值
        int result = 0;
        for (int i = 1; i < counts.size(); i++) {
            result += Math.min(counts.get(i), counts.get(i - 1));
        }

        return result;
    }
}

进行优化

class Solution {
    public int countBinarySubstrings(String s) {
        int n = s.length();
        int p = 0;

        int last = 0;
        int result = 0;
        // 用一个 last 临时变量进行存储
        while (p < n) {
            char ch = s.charAt(p);
            int count = 0;

            while (p < n && s.charAt(p) == ch) {
                count++;
                p++;
            }

            if (last == 0) {
                last = count;
            } else {
                result += Math.min(last, count);
                last = count;
            }
        }

        return result;
    }
}