生成给定字符串的所有字符串子集

时间:2014-04-18 06:13:32

标签: java string algorithm time-complexity

我想要一个代码来生成给定字符串的所有字符串子集。

我自己尝试了这个并提出了这个:

 public static void main(String[] args){
    long startTime = System.nanoTime(); 
    String text = "1234";
    int n = text.length();
    String k = "";
    for(int i=0;i < Math.pow(2, n);i++){
        k = Integer.toBinaryString(i);
        while(k.length() != n){
            k = "0"+k;
        }
        StringBuilder sb = new StringBuilder();
        for(int j=0;j<k.length();j++){
            if(k.charAt(j) == '1'){
                sb.append(text.charAt(j));
            }
        }
    //  System.out.println(String.format("%04d",
    //      Integer.parseInt(k)));
        System.out.println(sb.toString());
    }
    long endTime = System.nanoTime();
    long duration = endTime - startTime;
    System.out.println("Duration:" + duration);
}

但这是一个可怕的O(n ^ 2)算法,所以我一直在寻找更好的解决方案,并发现了这个:

public static void comb2(String s) { 
    comb2("", s);
}
private static void comb2(String prefix, String s) {
    System.out.println(prefix);
    for (int i = 0; i < s.length(); i++){
        comb2(prefix + s.charAt(i), s.substring(i + 1));
    }
}  


// read in N from command line, and print all subsets among N elements
public static void main(String[] args) {
   String alphabet = "1234";
   comb2(alphabet);
   System.out.println();
}

生成的输出是: 1 12 123 1234 124 13 134 14 2 23 234 24 3 34 4

虽然代码工作正常。我正在调试它以理解逻辑。我得到了如何生成1,12,123,1234,但之后不太清楚。能告诉我这里发生了什么吗?

5 个答案:

答案 0 :(得分:1)

您需要了解的是comb2方法的工作原理。基本上,它自称。这称为递归

当您拨打comb2(&#34; 1234&#34;)时,结果是对comb2的调用(&#34;&#34;,&#34; 1234&#34;)。

  • comb2(&#34;&#34;,&#34; 1234&#34;)打印&#34;&#34; (没有效果),然后开始循环 通过字符串的结尾(&#34; 234&#34;)。它做的第一件事 这个循环叫做comb2(&#34; 1&#34;,&#34; 234&#34;)。
  • comb2(&#34; 1&#34;,&#34; 234&#34;)打印&#34; 1&#34;,然后开始循环结束 字符串(&#34; 234&#34;)。它在这个循环中做的第一件事就是调用 COMB2(&#34; 12&#34;&#34; 34&#34)。
  • comb2(&#34; 12&#34;,&#34; 34&#34;)打印&#34; 12&#34;,然后开始循环结束 字符串(&#34; 34&#34;)。它在这个循环中做的第一件事就是调用 COMB2(&#34; 123&#34;&#34; 4&#34)。
  • comb2(&#34; 123&#34;,&#34; 4&#34;)打印&#34; 123&#34;,然后开始循环结束 字符串(&#34; 4&#34;)。它在这个循环中做的第一件事就是调用 COMB2(&#34; 1234&#34;&#34;&#34)。
  • comb2(&#34; 1234&#34;,&#34;&#34;)打印&#34; 1234&#34;,然后开始循环结束 字符串(&#34;&#34;)。由于无所事事,它会返回 立即给它的来电者:comb2(&#34; 123&#34;,&#34; 4&#34;)。
  • comb2(&#34; 123&#34;,&#34; 4&#34;)现在进入其循环的下一步。从那里 是没有,它返回。
  • comb2(&#34; 12&#34;,&#34; 34&#34;)现在进入其循环的下一步。它叫 COMB2(&#34; 124&#34;&#34;&#34)。
  • comb2(&#34; 124&#34;,&#34;&#34;)打印&#34; 124&#34;,然后开始循环结束 字符串(&#34;&#34;)。没有什么可做的,所以它会立即返回。

这是你从&#34; 1234&#34;至&#34; 124&#34;。希望,从那里,你应该能够理解整个执行过程。

答案 1 :(得分:0)

关键点是comb2(prefix + s.charAt(i), s.substring(i + 1)),为了更好地理解它,请用笛卡尔积的这个陈述进行类比,我认为这解决了所有问题。实际上,您可以创建所有以字符串开头的子字符串。

答案 2 :(得分:0)

这是一个时刻的涂鸦给我带来的:

import java.util.List;
import java.util.LinkedList;

public class subs {
    static List<String> allInitialSubstrings(String s) {
        List<String> r = new LinkedList<String>();
        for (int i=0; i<s.length(); i++) {
            r.add(s.substring(0, i+1));
        }
        return r;
    }

    static List<String> allSubstrings(String s) {
        List<String> r = new LinkedList<String>();
        for (int i=0; i<s.length(); i++) {
            r.addAll(allInitialSubstrings(s.substring(i)));
        }
        return r;
    }
    public static void main(String ... args) {
        System.out.println(allSubstrings(args[0]));
    }
}

~ $ javac subs.java 
~ $ java subs 12345
[1, 12, 123, 1234, 12345, 2, 23, 234, 2345, 3, 34, 345, 4, 45, 5]

如果你想要子集而不是子串,那么用Java这样的古老语言来编写它是一件非常痛苦的事情,但是这里只是一个稍微老一点的Python:

def allSubsets(s):
  if len(s):
    car = s[0]
    cdr = allSubsets(s[1:])
    return set([car + b for b in cdr]).union(cdr)
  else:
    return set([""])

allSubsets("12345")

答案 3 :(得分:0)

此程序应该可以正常工作

public static void getAllSubStrings(char[] chars,int start, Set allSubStrings){
    StringBuilder sb = new StringBuilder();
    if(start==chars.length){
        return;
    }
    for(int i=start;i<chars.length;i++){
        sb.append(chars[i]);
        allSubStrings.add(sb.toString());
    }
    getAllSubStrings(chars, start+1, allSubStrings);

}
public static void main(String[] args) {
    Set s = new TreeSet();
    getAllSubStrings("12345".toCharArray(), 0, s);
    System.out.println(s);
}

生成的输出为[1, 12, 123, 1234, 12345, 2, 23, 234, 2345, 3, 34, 345, 4, 45, 5]

从我认为这仍然是O(n2),因为它将运行n +(n-1)+(n-2)......次数是n(n + 1)/ 2我不&# 39;认为你可以比那更好

答案 4 :(得分:0)

没有任何for循环,具有相同逻辑的更干净的版本将是:

public static void printSubSets(String s){
    subSetsHelper(s, "");
}

private static void subSetsHelper(String s, String acc) {
    if (s.equals("")){
        System.out.println(acc);
        return;
    }
    subSetsHelper(s.substring(1), acc + s.charAt(0)); // accumulate 1st character
    subSetsHelper(s.substring(1), acc); // do not
}
  

printSubSets(“ abc”);   abc   b   交流电   一种   公元前   b   C   “”