等于目标值的多维数据集总数的计数。
对于少数集合,此代码有效(target
是100
对1000
)。当目标值增加时,系统将耗尽资源。我并没有拼凑allsets
只是为了根据需要创建和处理较小的子集。
如何按大小懒惰地创建/使用子集,直到一个大小的所有Sets
的总和等于或超过目标为止,此时不再需要检查,因为剩余的总和将大于目标。
val target = 100; val exp = 3; val maxi = math.pow(target, 1.0/exp).toInt;
target: Int = 100
exp: Int = 3
maxi: Int = 4
val allterms=(1 to maxi).map(math.pow(_,exp).toInt).to[Set];
allterms: Set[Int] = Set(1, 8, 27, 64)
val allsets = (1 to maxi).map(allterms.subsets(_).to[Vector]); allsets.mkString("\n");
allsets: scala.collection.immutable.IndexedSeq[Vector[scala.collection.immutable.Set[Int]]] = Vector(Vector(Set(1), Set(8), Set(27), Set(64)), Vector(Set(1, 8), Set(1, 27), Set(1, 64), Set(8, 27), Set(8, 64), Set(27, 64)), Vector(Set(1, 8, 27), Set(1, 8, 64), Set(1, 27, 64), Set(8, 27, 64)), Vector(Set(1, 8, 27, 64)))
res7: String =
Vector(Set(1), Set(8), Set(27), Set(64))
Vector(Set(1, 8), Set(1, 27), Set(1, 64), Set(8, 27), Set(8, 64), Set(27, 64))
Vector(Set(1, 8, 27), Set(1, 8, 64), Set(1, 27, 64), Set(8, 27, 64))
Vector(Set(1, 8, 27, 64))
allsets.flatten.map(_.sum).filter(_==target).size;
res8: Int = 1
此实现会丢失子集的大小分隔。
答案 0 :(得分:2)
您可以通过两种方式在计算中添加惰性:
combinations()
代替subsets()
。这样会创建一个Iterator
,因此直到需要时才实现组合(Int
值的集合)。Stream
(如果是Scala 2.13.0,则使用LazyList
),以便直到需要时才实现每个“行”(相同大小的组合)。然后,您可以利用以下事实来修整要实现的行数:每行的第一个组合将具有该行的最小sum
。
val target = 125
val exp = 2
val maxi = math.pow(target, 1.0/exp).toInt //maxi: Int = 11
val allterms=(1 to maxi).map(math.pow(_,exp).toInt)
//allterms = Seq(1, 4, 9, 16, 25, 36, 49, 64, 81, 100, 121)
val allsets = Stream.range(1,maxi+1).map(allterms.combinations)
//allsets: Stream[Iterator[IndexedSeq[Int]]] = Stream(<iterator>, ?)
// 11 rows, 2047 combinations, all unrealized
allsets.map(_.map(_.sum).buffered) //Stream[BufferedIterator[Int]]
.takeWhile(_.head <= target) // 6 rows
.flatten // 1479 combinations
.count(_ == target)
//res0: Int = 5