Java 0和1的字符串组合

Java 0和1的字符串组合,java,algorithm,data-structures,Java,Algorithm,Data Structures,我在一次采访中被问到这个问题: 给定由0、1和?组成的字符串s。问号可以 可以是0或1。查找字符串的所有可能组合 我提出了下面的代码,但我想知道这是否是解决问题的最佳方法,而且我对时间复杂性感到困惑 public static void main(String[] args) { List<String> output = new ArrayList<>(); addCombinations("0?1?", 0, output); System

我在一次采访中被问到这个问题:

给定由
0
1
组成的字符串s。问号可以 可以是
0
1
。查找字符串的所有可能组合

我提出了下面的代码,但我想知道这是否是解决问题的最佳方法,而且我对时间复杂性感到困惑

  public static void main(String[] args) {
    List<String> output = new ArrayList<>();
    addCombinations("0?1?", 0, output);
    System.out.println(output);
  }

  private static void addCombinations(String input, int index, List<String> output) {
    for (int i = index; i < input.length(); ++i) {
      if (input.charAt(i) == '?') {
        addCombinations(input.substring(0, i) + "0" + input.substring(i + 1), i + 1, output);
        addCombinations(input.substring(0, i) + "1" + input.substring(i + 1), i + 1, output);
        return;
      }
    }
    output.add(input);
  }
publicstaticvoidmain(字符串[]args){
列表输出=新的ArrayList();
添加组合(“0?1?”,0,输出);
系统输出打印项次(输出);
}
私有静态void addcompositions(字符串输入、int索引、列表输出){
for(int i=index;i
这里有一个不同的实现,它不使用递归,也不使用字符串连接

private static List<String> addCombinations(String input) {
    char[] chars = input.toCharArray();
    List<Integer> wildcardIndex = new ArrayList<>();
    for (int i = 0; i < chars.length; i++) {
        if (chars[i] == '?') {
            wildcardIndex.add(i);
            chars[i] = '0';
        }
    }
    if (wildcardIndex.size() > 31)
        throw new IllegalArgumentException("Too many wildcards (max 31): " + wildcardIndex.size());
    // Collections.reverse(wildcardIndex);
    List<String> output = new ArrayList<>(1 << wildcardIndex.size());
    NEXT: for (;;) {
        output.add(new String(chars));
        for (int i : wildcardIndex) {
            if (chars[i] == '0') {
                chars[i] = '1';
                continue NEXT;
            }
            chars[i] = '0';
        }
        break;
    }
    return output;
}
测试2

[000100010、110001、101011111]
测试3(使用
reverse()
调用未注释)

[000001010 011100101110111]

如果给定字符串中的问号为m,则可能的组合数为2^m。 那为什么呢

对于“”,答案是“0”,“1”

对于“?”,答案是“00”、“01”、“1,0”、“11”(将0和1与“?”=(“0”、“1”)的每个结果相加)

对于“?”,答案是“000”、“001”、“010”、“011”、“100”、“101”、“110”、“111”(将“?”的每个结果加上0和1)

当问号为1时,可能的组合数为2=2^1。
当问号为2时,可能的组合数为2*2=4=2^2。
当问号为3时,可能的组合数为4*2=8=2^3。
当问号为4时,可能的组合数为8*2=16=2^4。
当问号为5时,可能的组合数为16*2=32=2^5。
当问号为6时,可能的组合数为32*2=64=2^6。
当问号为7时,可能的组合数为64*2=128=2^7

因此,当问号为m时,可能的组合数为2^m

正如我们从二进制系统知道的,从0到(2^m)-1的每个数字都给出了二进制0和1的组合

当长度为1时,我们可以考虑0到(2 ^ 1)-1=1 < /P> 当长度为2时,我们可以考虑0到(2 ^ 2)-1=3 < /P> 当长度为3时,我们可以考虑0到(2 ^ 3)-1=7 < /P>

同样,对于长度m,我们可以考虑0到(2 ^ m)- 1。 所以我们可以取从0到(2^m)-1的每个数字

对于每个数字,我们将检查从0到m-1的每一位。
如果第i位为0,我们将把0放入第i个“?”。
如果第i位是1,我们将把1放在第i个“?”中


因此,我们将得到2^m不同的字符串

很难说什么是最好的还是不最好的。如果它可以工作,可以理解,并且没有非常差的性能,那么它可能是好的

下面是我写的一个简单的例子,它使用一些簿记来跟踪要填补的职位

publicstaticvoidmain(字符串[]args){
列出位字符串=生成(“0?1?0?11”);
forEach(System.out::println);
}
公共静态列表生成(字符串模式){
列表输出=新的ArrayList();
//起始位模板
字符串开始=pattern.replaceAll(“\\?”,“0”);
//获得可变位置。
int[]pos=IntStream.range(0,pattern.length()).filter(
i->pattern.charAt(i)='?').toArray();
//现在只需迭代2^n个可能性,其中
//n是可变位置的数量。
对于(inti=0;i<1>=1;
}
add(sb.toString());
}
返回输出;
}

您必须列出它们还是简单地计算数字?我们必须列出所有可能的输出。因此,我认为这个问题属于CodeReview,而不是StackOverflow。如果字符串的长度
n
m
是?那么这应该需要
O(n*2^m)
时间和内存。你不可能在时间上做得更好,提高内存的唯一方法是在找到组合时打印,而不是将它们累积到列表中。扩展btilly的评论:给出的可能组合数
m
问号是
2^m
。因此,如果字符串中有一个
,那么只有两个可能的输出。如果字符串中有两个
,四个输出,等等。由于字符串中有
n个
字符,因此输出字符的总数为
n*2^n
List<String> output = addCombinations("0?1?");
System.out.println(output);
System.out.println(addCombinations("???"));
System.out.println(addCombinations("???"));
0 0
1 1 
0 00
1 01
2 10
3 11
0 000
1 001
2 010
3 011
4 100
5 101
6 110
7 111