给定一个模式,我们需要通过填充模式中缺少的位置0和1来生成所有可能的二进制数。
E.g. Pattern = "x1x";
Output = [010, 110, 011, 111]
我通过创建方法calculate
解决了这个问题。
public static List<String> calculate(String input, int currentIndex) {
List<String> result = new ArrayList<String>();
if(currentIndex > input.length()-1) {
result.add("");
return result;
}
for(String fragment: calculate(input, currentIndex + 1)) {
if(input.charAt(currentIndex)=='x') {
result.add('0' + fragment);
result.add('1' + fragment);
}
else {
result.add(input.charAt(currentIndex) + fragment);
}
}
return result;
}
我们是否可以通过某种方式利用给定的模式并设计更快速和/或更清晰的解决方案。我已经知道非递归解决方案会更好。 Java 8的功能也很受欢迎。
答案 0 :(得分:4)
在反射时,使用递归和回调是更有效的方法。注意:这会创建非常少的对象(无论结果数量多少,都可能为3)。
public static void main(String[] args) {
printForPattern("x1x", System.out::println);
}
private static void printForPattern(String pattern, Consumer<CharSequence> consumer) {
printForPattern(pattern, new StringBuilder(), consumer);
}
private static void printForPattern(String pattern, StringBuilder sb, Consumer<CharSequence> consumer) {
int length = sb.length();
if (pattern.length() == length) {
consumer.accept(sb);
return;
}
char ch = pattern.charAt(length);
if (ch == 'x' || ch == '0') {
sb.append('0');
printForPattern(pattern, sb, consumer);
sb.setLength(length);
}
if (ch == 'x' || ch == '1') {
sb.append('1');
printForPattern(pattern, sb, consumer);
sb.setLength(length);
}
}
要将其添加到列表中,您可以执行
List<String> results = ...
printForPattern("x1x", s -> results.add(x.toString()));
你可以;
x
的数量。这是您需要迭代的位数。x
的所有可能位。x
与提供的位模式合并。答案 1 :(得分:2)
如果n
出现x
次出现,您可以通过将计数器从x
递增到{{1}来枚举0
位置的可能位组合}}。然后从计数器中取一个位来决定每个2^n - 1
是否应由x
或0
替换。
因此算法的轮廓是:
1
。x
循环到0
。
2^n - 1
。这仅限于63次出现x
,因为我们在x
的时候用完了房间。但是,无论如何,要花费超过2 ^ 63个解决方案需要非常长的时间,因此我认为这不是一个实际问题。
代码:
long
答案 2 :(得分:1)
public class Main {
static final class BinaryStringList extends AbstractList<String> {
private final char[] chars;
private final int size;
private final StringBuilder sb = new StringBuilder();
BinaryStringList(String pattern) {
chars = pattern.toCharArray();
int count = 0;
for (char c : chars) {
if (c != '0' && c != '1' && c != 'x') {
throw new IllegalArgumentException();
}
if (c == 'x') {
count++;
if (count > 30) {
throw new IllegalArgumentException();
}
}
}
size = (int) Math.pow(2, count);
}
@Override
public int size() {
return size;
}
@Override
public String get(int i) {
if (i < 0 || i >= size) { throw new IndexOutOfBoundsException(); }
sb.setLength(0);
int place = 0;
for (char a : chars) {
sb.append(a == 'x' ? ((i >> place++ & 1) == 0 ? '0' : '1') : a);
}
return sb.toString();
}
}
public static void main(String[] args) {
System.out.println(new BinaryStringList("0xx1x"));
}
}
这种方法的优点是实例化新的BinaryStringList
几乎是即时的。只有当你迭代它,它实际上做任何工作时才会这样做。
答案 3 :(得分:1)
虽然递归无疑更优雅,但是编写一个带有模式和二进制字符串的函数也很容易,并根据模式生成下一个二进制字符串。然后你只需要开始创建字符串,方法是将模式中的所有x
更改为0
s,然后迭代后继,直到你找到一个不是的字符串。有一个。
要查找给定模式的字符串的后继者,请向后遍历字符串和模式。在每个角色位置:
x
:
1
,请将其更改为0
。0
,请将其更改为1
并返回True。如果循环没有以return
终止,则没有后继函数,函数应该返回False。此时,字符串将重新初始化为初始值。
向后遍历模式/字符串会以字典顺序生成值。如果您不关心生成值的顺序,那么如果您向前迭代,代码可能会稍微简单一些。
在Java中,字符串是不可变的,因此您不能改变输入字符串。如果您需要创建字符串的副本,则无法返回上述算法指示返回的位置;你需要完成副本。如果你使用StringBuilder,那么在相反的方向上工作肯定会更容易。