August 13, 2018

4clojure 150 - Palindromic Numbers

A palindromic number is a number that is the same when written forwards or backwards (e.g., 3, 99, 14341).

Write a function which takes an integer n, as its only argument, and returns an increasing lazy sequence of all palindromic numbers that are not less than n.

The most simple solution will exceed the time limit!

From jafingerhut:

Note that all palindromic numbers are either of the form:

(concat x (reverse x))

for some sequence of one or more digits x, so the palindromic number has an even number of digits.

or:

(concat x [ d ] (reverse x))

for some sequence of digits x (perhaps empty) and some digit d, so the palindromic number has an odd number of digits. To generate the palindromic numbers in increasing order, we just need to make the sequence x (for even-length) or (concat x [d]) (for odd-length) represent incrementing decimal numbers.

Function next-pal returns the smallest palindromic number that is greater than or equal to its argument.

(ns live.test
  (:require [cljs.test :refer-macros [deftest is run-tests]]))

(defn pals [s]
  (let [p #(js/parseInt (apply str % ((if %2 next seq) (reverse (str %)))))
        d #(count (str %))
        o #(odd? (d %))
        b #(js/parseInt (subs (str %) 0 (quot (+ 1 (d %)) 2)))
        i #(let [x (b %)
                 o (o %)
                 y (+ 1 x)]
             (cond
              (= (d x) (d y)) (p y o)
              o (p (/ y 10) nil)
              1 (p y 1)))]
    (filter #(>= % s) (iterate i (p (b s) (o s))))))
             
(deftest pals-test
  (is (= (take 26 (pals 0))
     [0 1 2 3 4 5 6 7 8 9 
      11 22 33 44 55 66 77 88 99 
      101 111 121 131 141 151 161]))
  (is (= (take 16 (pals 162))
     [171 181 191 202 
      212 222 232 242 
      252 262 272 282 
      292 303 313 323]))
  (is (= (take 6 (pals 1234550000))
       [1234554321 1234664321 1234774321 
    1234884321 1234994321 1235005321]))
  (is (= (first (pals (* 111111111 111111111)))
     (* 111111111 111111111)))
  (is (= (set (take 199 (pals 0)))
     (set (map #(first (pals %)) (range 0 10000)))))
  (is (= true 
   (apply < (take 6666 (pals 9999999)))))
  (is (= (nth (pals 0) 10101)
     9102019)))
     
(run-tests)
Tags: coding exercises KLIPSE 4clojure Clojure