ちょっとコードがひどかったので書き直しましたw
手続き seven だけ再掲します。
(define (seven num) (define (iter n q r s k cnt) (if (= n 0) cnt (iter (quotient n 10) (quotient q 10) (remainder q 10) (+ s (* r (expt 10 k))) (+ k 1) (cond ((= r 7) (+ cnt (count-seven (* r (expt 10 k))) 1 s)) ((> r 7) (+ cnt (count-seven (* r (expt 10 k))) (expt 10 k))) (else (+ cnt (count-seven (* r (expt 10 k))))))))) (iter num (quotient num 10) (remainder num 10) 0 0 0))
ロジックの簡単な解説。
桁毎に処理するのですが、桁以下が 0 の時の切り番の 7 の数を数えるのが基本です。
たとえば、6543 で 1000 の位の桁の処理は、6000 までに 7 がいくつ現れるか計算します。
(count-seven 手続き)
以下特殊処理です。
・桁の数字が 7 のとき
下位の桁の数を足します。プラス 1 は補正です。
例えば、7543 で 7000 の桁を計算するときは、7000 までに 7 が現れる個数に 543 を足します。
さらに、7000 で 7 が 1 つ現れるので +1 して補正します。
・桁が 7 より大きいとき
例えば 8543 のときは、8000 までに 7 が現れる個数を求めますが 7000 番台分の 7 の出現個数を計算して足します。
・桁が 7 より小さいとき
例えば 5543 のときは、5000 までに 7 が現れる個数を普通に求めます。
という処理を下位の桁から上位の桁へ再帰的に行っています。
n が 0 になったら cnt を返して終了します。
プログラムの計算量は、数字の桁数に対し O(N) です。