美文网首页
40、字符串的组合

40、字符串的组合

作者: GIndoc | 来源:发表于2019-10-30 17:42 被阅读0次

题目:输入一个字符串(可能有重复字符),求它字符的所有组合。

例:
输入abc,结果为[bc, a, ab, b, ac, c, abc]
输入abac,结果为[aa, a, bc, ab, ac, b, aac, c, abc, aab, aabc]

解法一:每个字符都可选,可不选,即每个字符有两种可能,以abc举例,抽象成一棵二叉树,如下(带角标的代表不选,如 a'代表不选a ):


image.png(a'代表不选a)
  private List<String> combination(String str) {
        List<String> result = new ArrayList<>();
        if (str == null || str.length()==0) return result;
        dfs(result, "", 0, str.toCharArray());
        HashSet<String> set = new HashSet<>(result);    // 去重
        return new ArrayList<>(set);
    }

    /**
     * result 结果集
     * sb 当前组合起来的字符串
     * index 当前正在操作的字符的下标
     * str 字符数组
     **/
    private void dfs(List<String> result, String sb, int index, char[] str) {
        // 当最后一个字符已经操作完后,将组合后的字符串放入结果集
        if (index >= str.length) {
            if (sb.length() > 0) {      // 去除所有字符都不选的结果,即空字符串""
                // 将结果重新排序,方便后面去重
                char[] chars = sb.toCharArray();
                Arrays.sort(chars);
                result.add(new String(chars));
            }
            return;
        }
        // 不选index所在的字符
        dfs(result, sb, index + 1, str);
        // 选index所在的字符
        dfs(result, sb + str[index], index + 1, str);
    }

解法二:利用二进制,每个字符代表二进制中的一位,0代表不选,1代表选。例如:abc,用111表示,即用7=2^3-1 表示;a=100,b=010,c=001,ab=110,以此类推。共有7=2^3-1种可能。

private List<String> combination(String str) {
        List<String> result = new ArrayList<>();
        if (str == null || str.length()==0) return result;
        int max = (int) (Math.pow(2, str.length()) - 1);
        char[] chars = str.toCharArray();
        // i从1开始,去掉空字符串的可能
        for (int i = 1; i <= max; ++i) {
            getString(i, result, chars);
        }
        HashSet<String> strings = new HashSet<>(result);
        return new ArrayList<>(strings);
    }

    // 根据num确定哪些字符被选了,例如以abc举例,3=011,选了b和c
    private void getString(int num, List<String> result, char[] str) {
        // index表示当前在处理的字符下标,从最后一位字符开始
        int index = str.length - 1;    
        // 保存选中的字符下标,方便后面组合字符串
        List<Integer> indexes = new ArrayList<>();  
        // 将num模2,如果结果为1,说明index所在的字符被选中,将index放入indexes。
        // 然后将num右移一位(就是除2啦),同时将index-1指向前一个字符。
        // 重复此过程,直到num==0
        while (num != 0) {
            if (num % 2 == 1) {
                indexes.add(index);
            }
            num /= 2;
            --index;
        }
        StringBuilder sb = new StringBuilder();
        // 将选中的字符组合成字符串,并对字符重新排序,方便去重,然后放入结果集中
        for (int i = indexes.size() - 1; i >= 0; --i) {
            sb.append(str[indexes.get(i)]);
        }
        char[] chars = sb.toString().toCharArray();
        Arrays.sort(chars);
        result.add(new String(chars));
    }

相关文章

网友评论

      本文标题:40、字符串的组合

      本文链接:https://www.haomeiwen.com/subject/wsfavctx.html