Maximum Sum Subsequence
Programming Praxis | A collection of etudes, updated weekly, for the education and enjoyment of the savvy programmerというサイトにMaximum Sum Subsequence | Programming Praxisという問題があったので解いてみました。
cont-max2はほぼサイトに載っていた模範解答の最後のやつ(O(n)の解答)と同じでした。たcont-maxは最大値に加えて、最大になる部分数列も出力します。
数列を前から順番に見ていって、その時点での最大値と、一つ前の数列を使った最大値+今の値と、今の値を比較して大きい方を最大値に入れる、というのを繰り返してます。
(use gauche.collection) (define (cont-max lst) (define (initseq val) (cons (list val) val)) (let loop ((lst (cdr lst)) (prev-lst-max (initseq (car lst))) (max (initseq (car lst)))) (if (null? lst) max (let* ((new-lst-max (if (positive? (cdr prev-lst-max)) (cons (cons (car lst) (car prev-lst-max)) (+ (car lst) (cdr prev-lst-max))) (initseq (car lst))))) (loop (cdr lst) new-lst-max (find-max (list new-lst-max max) :key cdr)))))) (define (cont-max2 lst) (let loop ((lst (cdr lst)) (prev-lst-max (car lst)) (cur-max (car lst))) (if (null? lst) cur-max (let ((new-lst-max (if (positive? prev-lst-max) (+ prev-lst-max (car lst)) (car lst)))) (loop (cdr lst) new-lst-max (max cur-max new-lst-max)))))) gosh> (cont-max '(31 -41 59 26 -53 58 97 -93 -23 84)) ((97 58 -53 26 59) . 187) gosh> (cont-max2 '(31 -41 59 26 -53 58 97 -93 -23 84)) 187
そういえば模範解答は最大値の初期値を0にしてしまっているので、最初の値が負の場合は、上手くいかない場合があります。
gosh> (max-sum-subsequence '(-31 -32 -123 -32)) 0
どう見ても0ではない...
(10/12/07追記)
コメントにて、部分列は空列を含むので、空列の和を0とすると模範解答は正しいのではないかという指摘を受けました。言われてみると、確かにそう考えるほうが自然ですね。そうすると上の回答は間違ってて、loopのprev-lst-maxとcur-maxの初期値を0にしてlstの初期値をlstにしなければなりません。