You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在Guile中用动态规划解决硬币找零问题:如何生成正确组合列表?

硬币找零问题的Guile Lisp实现方案

一、生成有效硬币组合列表的修正

你的代码存在两个核心问题:终止条件处理不当,以及递归返回的列表嵌套未扁平化。以下是修正后的实现:

1. 生成所有排列(考虑硬币顺序,如(2,3)和(3,2)视为不同组合)

(define (get-coins coins target)
  (cond
    ((= target 0) '(()))  ; 找到有效组合:空列表代表0个硬币,用列表包裹以便后续cons
    ((< target 0) '())     ; 金额为负,无有效组合,返回空列表
    (else
     ; 使用append-map替代map,将每个硬币生成的组合列表扁平化合并
     (append-map (lambda (coin)
                   ; 给每个递归得到的组合前添加当前硬币
                   (map (lambda (comb) (cons coin comb))
                        (get-coins coins (- target coin))))
                 coins))))

调用(get-coins '(2 3) 6)会返回:((2 2 2) (2 3) (3 2) (3 3))

2. 生成无重复组合(不考虑顺序,仅保留如(2,2,2)和(3,3))

如果需要避免重复排列,可通过限制递归时的硬币选择范围实现:

(define (get-coins coins target)
  (define (helper remaining-coins current-target)
    (cond
      ((= current-target 0) '(()))
      ((or (null? remaining-coins) (< current-target 0)) '())
      (else
       (append
        ; 选择当前硬币:继续用剩余硬币(含当前),金额减去硬币值
        (map (lambda (comb) (cons (car remaining-coins) comb))
             (helper remaining-coins (- current-target (car remaining-coins))))
        ; 不选当前硬币:递归处理剩下的硬币,金额不变
        (helper (cdr remaining-coins) current-target)))))
  (helper coins target))

调用(get-coins '(2 3) 6)会返回:((2 2 2) (3 3)),与你预期的结果一致。

二、动态规划求最少硬币数(高效解法)

生成所有组合仅适合小金额场景,针对大金额,用递归+记忆化(Memoization)的动态规划更高效:

(define (coin-change coins amount)
  (define memo (make-hash-table))  ; 用哈希表缓存已计算的金额结果

  (define (min-coins target)
    (cond
      ((hash-ref memo target #f) => identity)  ; 命中缓存直接返回
      ((= target 0) 0)                          ; 0金额需要0个硬币
      ((< target 0) #f)                         ; 无效情况返回#f标记
      (else
       ; 收集所有有效硬币的递归结果,计算当前金额的最少硬币数
       (let ((candidates
              (filter identity
                      (map (lambda (coin)
                             (let ((res (min-coins (- target coin))))
                               (and res (+ res 1))))  ; 有效则加1(当前硬币)
                           coins))))
         (let ((result (if (null? candidates) #f (apply min candidates))))
           (hash-set! memo target result)  ; 存入缓存
           result)))))

  (let ((res (min-coins amount)))
    (if res res -1)))  ; 有效返回结果,无效返回-1
  • 调用(coin-change '(2 3) 6)返回2(最少硬币数为2)
  • 调用(coin-change '(2) 5)返回-1(无法凑成)

内容的提问来源于stack exchange,提问作者Kyle Baldwin

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.07 20:55:25