Created
April 16, 2015 21:00
-
-
Save Engelberg/7a36892f9453d73a6303 to your computer and use it in GitHub Desktop.
Memoizing count-combinations
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
;; gorilla-repl.fileformat = 1 | |
;; @@ | |
(ns count-combinations) | |
;; @@ | |
;; => | |
;;; {"type":"html","content":"<span class='clj-nil'>nil</span>","value":"nil"} | |
;; <= | |
;; ** | |
;;; This is your implementation of count-combinations: | |
;; ** | |
;; @@ | |
(defn count-combinations [total denom] | |
(cond (= total 0) 1 | |
(or (< total 0) (empty? denom)) 0 | |
:else (+ (count-combinations total (rest denom)) | |
(count-combinations (- total (first denom)) denom)))) | |
;; @@ | |
;; => | |
;;; {"type":"html","content":"<span class='clj-var'>#'count-combinations/count-combinations</span>","value":"#'count-combinations/count-combinations"} | |
;; <= | |
;; ** | |
;;; It's slow for large totals. | |
;; ** | |
;; @@ | |
(count-combinations 1324 [1 5 10 25]) | |
;; @@ | |
;; => | |
;;; {"type":"html","content":"<span class='clj-long'>322578</span>","value":"322578"} | |
;; <= | |
;; @@ | |
(time (count-combinations 1324 [1 5 10 25])) | |
;; @@ | |
;; -> | |
;;; "Elapsed time: 8310.394583 msecs" | |
;;; | |
;; <- | |
;; => | |
;;; {"type":"html","content":"<span class='clj-long'>322578</span>","value":"322578"} | |
;; <= | |
;; ** | |
;;; We can speed it up with memoization. First, we need to tell Clojure this is a dynamic var. Other than the addition of `^:dynamic`, this is exactly your code. | |
;; ** | |
;; @@ | |
(defn ^:dynamic count-combinations [total denom] | |
(cond (= total 0) 1 | |
(or (< total 0) (empty? denom)) 0 | |
:else (+ (count-combinations total (rest denom)) | |
(count-combinations (- total (first denom)) denom)))) | |
;; @@ | |
;; => | |
;;; {"type":"html","content":"<span class='clj-var'>#'count-combinations/count-combinations</span>","value":"#'count-combinations/count-combinations"} | |
;; <= | |
;; ** | |
;;; Now we can write the faster version as a memoization wrapper around your implementation. | |
;; ** | |
;; @@ | |
(defn count-combinations-fast [total denom] | |
(binding [count-combinations (memoize count-combinations)] | |
(last (for [i (range (inc total))] | |
(count-combinations i denom))))) | |
;; @@ | |
;; => | |
;;; {"type":"html","content":"<span class='clj-var'>#'count-combinations/count-combinations-fast</span>","value":"#'count-combinations/count-combinations-fast"} | |
;; <= | |
;; @@ | |
(time (count-combinations-fast 1324 [1 5 10 25])) | |
;; @@ | |
;; -> | |
;;; "Elapsed time: 23.5844 msecs" | |
;;; | |
;; <- | |
;; => | |
;;; {"type":"html","content":"<span class='clj-long'>322578</span>","value":"322578"} | |
;; <= | |
;; @@ | |
;; @@ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment