【问题标题】:Filter a list for sums筛选总和列表
【发布时间】:2013-07-09 05:41:28
【问题描述】:

我需要编写一个函数,它使用整数列表 lst 并生成一个列表,该列表仅包含 lst 的唯一元素(无特定顺序),这些元素是 lst 中任何两个其他元素的总和。

例如:

(sumfilt '(1 4 7 5 17 11)) => '(11 5)
(sumfilt '(5 4 7 5 9 1 10)) => '(5 9 10)

有人可以帮我解决这个问题吗?我也希望这样做尽可能高效

【问题讨论】:

  • 到目前为止,除了来这里让我们做你的功课之外,你还尝试过什么?给我们看一些代码!
  • 我只是制定了我认为应该是的。我打算创建另一个函数来消耗列表的第一个值,然后取出列表的其余部分,看看是否有任何 2 个值构成了第一个值。不过,我仍在考虑这个问题,不确定这是否是最有效的方法。
  • 然后继续思考,然后返回一些代码。 cfr stackoverflow.com/questions/how-to-ask 看看什么是可接受的问题。

标签: scheme racket


【解决方案1】:

我会给你一些提示来解决这个问题。第一种天真的方法是预先计算输入列表的每个大小为 2 组合的总和列表,然后测试以查看输入列表的哪些元素属于总和列表。最后一步,删除重复项。

假设存在一个comb 过程来计算lst 列表与给定大小m 的所有可能组合(查找它,或者自己实现它!),这里有一个非常简短的问题答案,实现上面解释的朴素算法——这对于包含 1000 个左右元素的列表应该已经足够了:

(require srfi/26) ; I like to use `cut`, but `lambda` would serve just as well

(define (comb lst m)
  <???>) ; ToDo: generate all m-size combinations of lst

(define (sumfilt lst)
  (let ((sums (map (cut apply + <>) (comb lst 2))))
    (remove-duplicates (filter (cut member <> sums) lst))))

或者等效地,使用cute 仅对预先计算的总和列表进行一次评估:

(define (sumfilt lst)
  (remove-duplicates
   (filter (cute member <> (map (cut apply + <>) (comb lst 2))) lst)))

更有效的方法将涉及subset sum 问题的一些变体,通过动态规划解决。不过,这样的解决方案编写起来会更复杂。不管怎样,别忘了测试你的答案:

(sumfilt '(1 4 7 5 17 11)) 
=> '(5 11)

(sumfilt '(5 4 7 5 9 1 10)) 
=> '(5 9 10)

【讨论】:

    【解决方案2】:

    由于您的问题被标记为 Racket,我想建议使用 Racket 成语的解决方案:

    allsums 按照 Oscar 的建议创建所有总和的列表。它基本上是一个嵌套循环,处理所有必要的组合。为了不重复,我使用了一个 set ,它在添加时会默默地删除它们。稍后该集合被转换为列表。

    (define (allsums lst)
      (let* ([len (length lst)] [len-1 (sub1 len)])
        (set->list
         (for*/set ([i (in-range 0 len-1)]
                    [j (in-range (add1 i) len)])
           (+ (list-ref lst i) (list-ref lst j))))))
    

    sumfilt 现在根据 allsums 生成的列表过滤您的列表。同样,使用集合来删除重复项:

    (define (sumfilt lst)
      (let ([as (allsums lst)])
        (set->list
         (for/set ([i lst] #:when (member i as))
           i))))
    

    > (sumfilt '(1 4 7 5 17 11))
    '(5 11)
    > (sumfilt '(5 4 7 5 9 1 10))
    '(5 9 10)
    

    但如果你需要一个纯 Scheme 解决方案,这段代码就可以了,只使用经典形式和习语:

    (define (allsums lst)
      (let loop1 ((lst lst) (res '()))
        (if (empty? lst)
            (reverse res)
            (let loop2 ((a (car lst)) (bs (cdr lst)) (res res))
              (if (empty? bs)
                  (loop1 (cdr lst) res)
                  (let ((s (+ a (car bs))))
                    (loop2 
                     a 
                     (cdr bs) 
                     (if (member s res) res (cons s res)))))))))
    
    (define (sumfilt lst)
      (let ((as (allsums lst)))
        (let loop ((lst lst) (res '()))
          (if (empty? lst)
              (reverse res)
              (let ((ca (car lst)))
                (loop 
                 (cdr lst) 
                 (if (and (member ca as) (not (member ca res)))
                     (cons ca res)
                     res)))))))
    

    给予

    > (sumfilt '(1 4 7 5 17 11))
    '(5 11)
    > (sumfilt '(5 4 7 5 9 1 10))
    '(5 9 10)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多