📌  相关文章
📜  查找使用给定字符串的不同字符形成的字符串数(1)

📅  最后修改于: 2023-12-03 15:10:43.669000             🧑  作者: Mango

查找使用给定字符串的不同字符形成的字符串数

问题描述

给定一个字符串,求由该字符串中不同字符组成的字符串数。

例如,对于字符串 "hello",由不同字符组成的字符串有 "h", "e", "l", "o", "he", "hl", "ho", "el", "eo", "lo", "hel", "heo", "hlo", "elo", "helo",共 15 种。

解决方案
方案一:暴力枚举

我们可以先把所有可能组成的字符串枚举出来,然后用 HashSet 去重。

具体来说,我们可以从字符串的第 1 个字符开始遍历,每次把当前字符与后面的字符组合,如果是新出现的组合就加入到 HashSet 中。

时间复杂度为 O(n^2),其中 n 是字符串的长度。

public static int countUniqueStrings(String str) {
    Set<String> set = new HashSet<>();
    for (int i = 0; i < str.length(); i++) {
        for (int j = i + 1; j <= str.length(); j++) {
            String sub = str.substring(i, j);
            if (!set.contains(sub)) {
                set.add(sub);
            }
        }
    }
    return set.size();
}
方案二:位运算 + 哈希表

我们可以将每个字符映射到一个二进制位上,例如 'a' 对应第 0 位,'b' 对应第 1 位,以此类推。

然后,对于一个子串,可以用一个整数来表示其中每个字符是否出现过。例如,对于子串 "abc",可以表示为二进制数 0b111,即第 0、1、2 位都为 1。

最后,将所有不同的子串对应的整数放入一个 HashSet 中,最终 HashSet 的大小就是答案。

这种方法的时间复杂度为 O(n 2^n),其中 n 是字符集大小。可以看做是对子串进行组合的一个穷举。

public static int countUniqueStrings(String str) {
    int n = str.length();
    int[] cnt = new int[26];
    // 对每个字符进行编号
    for (int i = 0; i < n; i++) {
        cnt[str.charAt(i) - 'a'] = 1;
    }
    int u = 1 << 26;
    Set<Integer> set = new HashSet<>();
    // 枚举所有子集
    for (int i = 0; i < u; i++) {
        int mask = 0;
        for (int j = 0; j < 26; j++) {
            if ((i & (1 << j)) != 0) {
                if (cnt[j] == 1) {
                    mask |= 1 << j;
                } else {
                    // 如果某个字符在子集中出现了多次,则直接跳过
                    mask = 0;
                    break;
                }
            }
        }
        if (mask != 0) {
            set.add(mask);
        }
    }
    return set.size();
}
总结

以上两种方法,第一种方法比较容易理解和实现,但时间复杂度较高;第二种方法时间复杂度更低,但需要进行位运算处理。如果字符集较小,那么使用第二种方法可能更优,否则还是建议使用第一种方法。