美文网首页
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