您可以通过先计算所有可能性然后对它们进行排序来解决这个问题。如果你能发现一个有趣的规则,找到所有的可能性并不是那么复杂。举个例子:
a
=======
[a]
如果您只有一个输入 a,则唯一可能的结果是 [a]。
a, b
==============
[a] [a, b]
[b]
如果您的输入为 a, b,则有 3 个可能的结果:[a], [b], [a, b]。
这是我们发现规则 1 的地方:单个元素 ([a]) 的可能性是a, b 中可能性的子集。或概括:
上一个结果中的所有可能性都将包含在当前结果中。
让我们看看这是否适用于a, b, c:
a, b a, b, c
================== =============================
-------------- -------------
| [a] [a, b] | | [a] [a, b] |
| [b] | | [b] |
|--------------| |-------------| [a, b, c]
[c] [a, c]
[b, c]
您可以针对更大的输入验证这一点,但它始终成立。如果你从长远来看,这一切都是有道理的。潜在 n 的所有组合将是:n-1 的所有组合 + 更多。
但这里还有一条更有趣的规则。
如果你有这样的输入:
a, b
==============
[a] [a, b]
[b]
您可以创建一个算法来计算下一个。首先创建前一个的副本(因为上面的规则):
a, b, c
==============
[a] [a, b]
[b]
对于第一行,您只需添加“最后一个”下一个字母。由于下一个是a, b, c,所以你需要添加到第一行的是:c:
a, b, c
==============
[a] [a, b]
[b]
[c]
对于第二行,您取上一行(减去添加的c),附加“最后一个”下一个字母并插入它。那就是:
a, b, c
===================
[a] <-| [a, b]
[b] |-> [a, c] <-- "a" came from the previous row, "c" was added as the last one
[c]
一些b:
a, b, c
===================
[a] [a, b]
[b] <-| [a, c]
[c] |-> [b, c] <-- "b" came from the previous row, "c" then added as the last one
对于最后一行,我们只需添加所有“下一行”(a, b, c):
a, b, c
=================================
[a] [a, b]
[b] [a, c] [a, b, c]
[c] [b, c]
使用上述相同的逻辑,您可以计算a, b, c, d的结果:
先复制:
a, b, c, d
=================================
[a] [a, b]
[b] [a, c] [a, b, c]
[c] [b, c]
添加d:
a, b, c, d
=================================
[a] [a, b]
[b] [a, c] [a, b, c]
[c] [b, c]
[d]
取上一行并追加:
a, b, c, d
=================================
[a] [a, b]
[b] [a, c] [a, b, c]
[c] [b, c]
[d] [a, d]
[b, d]
[c, d]
再次,取上一行并追加(记住:“除了添加的那一行”):
a, b, c, d
=================================
[a] [a, b]
[b] [a, c] [a, b, c]
[c] [b, c] [a, b, d] <--- [a, b] + [d]
[d] [a, d] [a, c, d] <--- [a, c] + [d]
[b, d] [b, c, d] <--- [b, c] + [d]
[c, d]
最后一个:
a, b, c, d
=================================================
[a] [a, b]
[b] [a, c] [a, b, c]
[c] [b, c] [a, b, d]
[d] [a, d] [a, c, d] [a, b, c, d]
[b, d] [b, c, d]
[c, d]
如果您了解上面发生的情况,那就是编写代码。我所做的唯一更改是不添加我已经知道将无法通过max 的检查的元素。在这里,它看起来很复杂,但实际上它相当微不足道(除了一些边缘情况):
static List<String> partitions(List<Choice> all, int max) {
ArrayList<ArrayList<ArrayList<Choice>>> previousResult = new ArrayList<>();
ArrayList<ArrayList<ArrayList<Choice>>> currentResult = new ArrayList<>();
int i = 0;
for(;i<all.size();++i) {
// add the first element
Choice current = all.get(i);
if(currentResult.isEmpty()) {
if(less(List.of(current), max)) {
// looks complicated, but all it does is adds a single element in the first index
ArrayList<Choice> inner = new ArrayList<>();
inner.add(current);
ArrayList<ArrayList<Choice>> in = new ArrayList<>();
in.add(inner);
currentResult.add(in);
previousResult.add(in);
}
} else {
if(less(List.of(current), max)) {
ArrayList<Choice> element = new ArrayList<>();
element.add(current);
currentResult.get(0).add(element);
}
if(currentResult.size() > 1) {
for(int j=0;j<i-1;++j) {
if(j < previousResult.size()) {
ArrayList<ArrayList<Choice>> p = previousResult.get(j);
for(int d=0;d<=p.size()-1;++d){
ArrayList<Choice> copy = new ArrayList<>(p.get(d));
copy.add(all.get(i));
if(less(copy, max)){
currentResult.get(j).add(copy);
}
}
}
}
}
// add tail if possible
ArrayList<ArrayList<Choice>> tail = new ArrayList<>();
ArrayList<Choice> t = new ArrayList<>(all.subList(0, i + 1));
if(less(t, max)) {
tail.add(t);
currentResult.add(tail);
}
if(currentResult.size() == 1) {
ArrayList<Choice> l = currentResult.get(0).stream().flatMap(List::stream).collect(Collectors.toCollection(ArrayList::new));
if(less(l, max)) {
tail.add(l);
currentResult.add(tail);
}
}
// smart copy here
previousResult = copy(previousResult, currentResult);
}
}
return
currentResult.stream()
.flatMap(List::stream)
.map(list -> {
int sum = list.stream().mapToInt(Choice::getCost).sum();
List<String> l = list.stream().map(Choice::getKey).collect(Collectors.toList());
return new AbstractMap.SimpleEntry<>(sum, l);
})
.sorted(Map.Entry.<Integer, List<String>>comparingByKey().reversed())
.filter(x -> x.getKey() <= max)
.map(Map.Entry::getValue)
.findFirst()
.orElse(List.of());
}
private static ArrayList<ArrayList<ArrayList<Choice>>> copy(ArrayList<ArrayList<ArrayList<Choice>>> previousResult, ArrayList<ArrayList<ArrayList<Choice>>> currentResult) {
return currentResult.stream()
.map(x -> x.stream().map(y -> (ArrayList<Choice>)y.clone()).collect(Collectors.toCollection(ArrayList::new)))
.collect(Collectors.toCollection(ArrayList::new));
}
private static boolean less(List<Choice> in, int max) {
return in.stream().mapToInt(Choice::getCost).sum() <= max;
}