以下程序使用具有开始和结束的规则.允许规则重叠,以便可以在2个或更多规则中使用1.如果这不是您想要的,那么修改代码将非常容易.
如果1的数量很小,它应该非常快,但它不能很好地扩展.
它不是很“聪明”.它所做的只是尽可能在每个阶段淘汰尽可能多的人.这种方法不是最优的,但在大多数情况下应该非常好.例如,如果你开始
1 1 1 1 1 0 1 1 1 1 1
找到的第一条规则是
Every 2th, starting at 1, ending at 11.
因为它使用了六个.但是,最好的解决方案显然只需要两个涉及五个1的规则.我认为找到一个始终能找到最佳答案的有效算法是非常困难的.
public static void main(String[] args) {
rulesFor(0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 0);
}
public static void rulesFor(int... arr) {
Set allOnes = new HashSet<>();
for (int i = 0; i < arr.length; i++)
if (arr[i] == 1)
allOnes.add(i);
// Size 1 has to be done separately as the below code wouldn't work.
if (allOnes.size() == 1) {
int a = allOnes.iterator().next();
System.out.println("Every 1st, starting at " + (a + 1) + ", ending at " + (a + 1) + ".");
return;
}
Set leftToRemove = new HashSet<>(allOnes);
while (!leftToRemove.isEmpty()) {
int low = -1;
int high = -1;
int d = -1;
int removeTotal = -1;
for (int a : leftToRemove) {
for (int b : allOnes) {
if (b == a)
continue;
int d2 = Math.abs(b - a);
int low2 = a;
int high2 = a;
int removeTotal2 = 1;
while (true) {
if (!allOnes.contains(low2 - d2))
break;
low2 -= d2;
if (leftToRemove.contains(low2))
removeTotal2++;
}
while (true) {
if (!allOnes.contains(high2 + d2))
break;
high2 += d2;
if (leftToRemove.contains(high2))
removeTotal2++;
}
if (removeTotal2 > removeTotal) {
low = low2;
high = high2;
removeTotal = removeTotal2;
d = d2;
}
}
}
System.out.println("Every " + d + "th, starting at " + (low + 1) + ", ending at " + (high + 1) + ".");
for (int i = low; i <= high; i += d)
leftToRemove.remove(i);
}
}