在一次采访中有人问我这个问题:
给出由
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);
}
答案 0 :(得分:0)
很难说什么是最好的。如果它可以正常工作,可以理解并且性能不差,那么可能就可以了。
这是我写的一个简单的书,它使用一些簿记来跟踪要填补的职位。
public static void main(String[] args) {
List<String> bitStrings = generate("0?1?0?11");
bitStrings.forEach(System.out::println);
}
public static List<String> generate(String pattern) {
List<String> output = new ArrayList<>();
//Starting bit template
String start = pattern.replaceAll("\\?", "0");
//get the changeable positions.
int[] pos = IntStream.range(0, pattern.length()).filter(
i -> pattern.charAt(i) == '?').toArray();
// Now simply iterate thru the 2^n possibilities where
// n is the number of changeable positions.
for (int i = 0; i < 1 << pos.length; i++) {
StringBuilder sb = new StringBuilder(start);
int p = i;
for (int k = 0; k < pos.length; k++) {
sb.setCharAt(pos[k], (char) ((p & 1) + '0'));
p >>= 1;
}
output.add(sb.toString());
}
return output;
}
答案 1 :(得分:-1)
这是一种不使用递归并且不使用字符串连接的实现。
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;
}
测试1
List<String> output = addCombinations("0?1?");
System.out.println(output);
[0010, 0110, 0011, 0111]
测试2
System.out.println(addCombinations("???"));
[000, 100, 010, 110, 001, 101, 011, 111]
测试3(不带reverse()
调用)
System.out.println(addCombinations("???"));
[000, 001, 010, 011, 100, 101, 110, 111]
答案 2 :(得分:-1)
如果给定字符串中问号的数量为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
0 0
1 1
所以当长度为2时,我们可以考虑0到(2 ^ 2)-1 = 3
0 00
1 01
2 10
3 11
因此,当长度为3时,我们可以考虑0到(2 ^ 3)-1 = 7
0 000
1 001
2 010
3 011
4 100
5 101
6 110
7 111
类似地,对于长度m,我们可以考虑0到(2 ^ m)-1。
所以我们可以取0到(2 ^ m)-1的每个数字。
对于每个数字,我们将检查从0到m-1的每一位。
如果第ith位为0,我们将在ith'?'中放入0。
如果第ith位为1,我们将在ith'?'中放入1。
因此,我们将得到2 ^ m个不同的字符串。