有两件事使这个问题成为可能:
- 输入可以被截断为大小 O(sqrt(n))。没有负输入,因此您可以丢弃任何大于 100*sqrt(n) 的数字,并且所有输入都是不同的,因此我们知道最多有 100*sqrt(n) 输入很重要。
- 比赛场地的大小为 O(sqrt(n))。尽管有 O(2^sqrt(n)) 方法可以组合重要的 O(sqrt(n)) 输入,但您不必关心离开 100*sqrt(n) 范围或冗余命中的组合你已经可以达到的目标。
基本上,这个问题尖叫着动态编程,每个输入都以某种方式针对“到达数字”空间的每个部分进行检查。
解决方案最终是确保数字不会脱离自身(通过在正确的方向上扫描),只查看每个数字一次,并为我们自己提供足够的信息以在之后重建解决方案。
下面是一些应该在给定时间内解决问题的 C# 代码:
int[] FindSubsetToImpliedTarget(int[] inputs) {
var target = 100*(int)Math.Ceiling(Math.Sqrt(inputs.Count));
// build up how-X-was-reached table
var reached = new int?[target+1];
reached[0] = 0; // the empty set reaches 0
foreach (var e in inputs) {
// we go backwards to avoid reaching off of ourselves
for (var i = target; i >= e; i--) {
if (reached[i-e].HasValue) {
reached[i] = e;
}
}
}
// was target even reached?
if (!reached[target].HasValue) return null;
// build result by back-tracking via the logged reached values
var result = new List<int>();
for (var i = target; reached[i] != 0; i -= reached[i].Value) {
result.Add(reached[i].Value);
}
return result.ToArray();
}
我还没有实际测试过上面的代码,所以要小心拼写错误和错误。