在这个问题中,您将获得一个值V和一个唯一整数列表。您的工作是找到大小为4的不同子集的数量,总计为V.列表中的每个元素只能使用一次。如果找不到这样的子集,则输出0。
例如,如果整数为[3, 4, 5, 6, 7, 8, 9, 10]
且值为30
,则输出应为5.子集为:
[3, 8, 9, 10]
[4, 7, 9, 10]
[5, 6, 9, 10]
[5, 7, 8, 10]
[6, 7, 8, 9].
解决这个问题并不难,最直接的方法是将for循环嵌套四次。 Clojure的做法是什么?
答案 0 :(得分:5)
我将如何做到这一点:
(ns example.solve
(:require [clojure.math.combinatorics :as combo]))
(defn solve
[s n v]
(filter (comp (partial = v)
(partial reduce +))
(combo/combinations s n)))
我在我的示例中使用math.combinatorics
,因为这是从列表中获取4个元素的所有组合的最简单方法。
以下是使用solve
:
=> (solve [3 4 5 6 7 8 9 10] 4 30)
((3 8 9 10) (4 7 9 10) (5 6 9 10) (5 7 8 10) (6 7 8 9))
答案 1 :(得分:3)
我会使用clojure.map.combinatorics/combinations
来获取所有4个元素的子集,然后使用filter
来获取那些不总和为V的子集。
答案 2 :(得分:3)
有趣的是,这个问题承认了一个(双重?)递归解决方案,它只涉及求和和计数(没有实际生成子集。)
如果你看一下初始元素3,那么解的一部分是从序列的其余部分中的3个元素中得到的和的数量,其中总和是27,这是相同问题的较小形式,因此可以以递归方式解决。递归的底部是当您查找从1个元素生成的总和时,归结为简单检查以查看所需的总和是否在列表中。
解决方案的另一部分涉及查看下一个元素4,在列表的其余部分中查找超过4等于26的总和,依此类推......此部分也可以递归处理。
将它作为递归函数放在一起如下所示,它为示例序列生成所需的答案5。
(defn solve [xs n len]
(if (seq xs)
(if (= len 1)
(if (some #{n} xs) 1 0)
(+ (solve (rest xs)
(- n (first xs))
(dec len))
(solve (rest xs)
n
len)))
0))
(solve [3 4 5 6 7 8 9 10] 30 4)
;=> 5
答案 3 :(得分:1)
就直接回答问题而言,以下是使用索引和for循环的方法:
(defn solve-for [xs v]
(for [ndx0 (range 0 (- (count xs) 3))
ndx1 (range (inc ndx0) (- (count xs) 2))
ndx2 (range (inc ndx1) (- (count xs) 1))
ndx3 (range (inc ndx2) (count xs))
:when (= v (+ (xs ndx0) (xs ndx1) (xs ndx2) (xs ndx3)))]
(list (xs ndx0) (xs ndx1) (xs ndx2) (xs ndx3))))
FWIW,这比使用clojure.math.combinatorics
的方法快约70%,但是比双递归解决方案慢两倍。