The Next Palindrome
May 22, 2009
This exercise comes originally from the Sphere Online Judge; I read it on Proggit based on a blog posting by Chethan T. So many of the answers were wrong that I decided it would make a good exercise for Programming Praxis. Here is SPOJ’s statement of the exercise:
A positive integer is called a palindrome if its representation in the decimal system is the same when read from left to right and from right to left. For a given positive integer K of not more than 1000000 digits, write the value of the smallest palindrome larger than K to output. Numbers are always displayed without leading zeros.
Your task is to write a function that calculates the next palindrome larger than its input. When you are finished, you are welcome to read or run a suggested solution, or post your own solution or discuss the exercise in the comments below.
;; It doesn’t need to be that complicated.
;; Below is a simpler solution
(define (next-palindrome n)
(define (next-palindrome* n)
(define digits-of-n (string->list (format “~a” n)))
(cond
[(equal? digits-of-n (reverse digits-of-n)) n]
[else (next-palindrome* (add1 n))]))
(next-palindrome* (add1 n)))
(map next-palindrome ‘(0 88 808 1999 2133 9999 99999)) ==> ‘(1 99 818 2002 2222 10001 100001)
Here’s how I did it:
bisect xs = go xs xs where
go xs [] = ([],[],xs)
go (x:xs) (_:[]) = ([],[x],xs)
go (x:xs) (_:_:ys) = let (fs,m,ss) = go xs ys in (x:fs,m,ss)
increment = foldr go ([],True) where
go ‘9’ (xs,True) = (‘0′:xs,True)
go x (xs,True) = (succ x:xs,False)
go x (xs,False) = (x:xs,False)
nextPalindrome xs | fhr > secondHalf = firstHalf ++ middle ++ fhr
| otherwise = startInc ++ endInc where
(firstHalf, middle, secondHalf) = bisect xs
fhr = reverse firstHalf
(incremented, carry) = increment (firstHalf ++ middle)
incremented’ | carry = ‘1’:incremented
| otherwise = incremented
startInc | carry = init incremented’
| otherwise = incremented’
endInc | null middle = reverse incremented’
| otherwise = tail (reverse incremented’)
It’s a bit fiddly, but there’s only really two cases: first half reversed > second half: take the palindrome starting with the first half. first half reversed <= second half: take the palindrome starting with the first half plus one (being careful to drop a digit if we increase the length in so doing).
;; Hopefully. Better formated
@Jaime Vargas: note the problem requires this to work on inputs 1000000 digits. Try your program on (10^500000 – 1) * (10^500000).
Once more with formatting?
[…] Praxis – The Next Palindrome By Remco Niemeijer Today’s Programming Praxis problem is about palindromic numbers, i.e. numbers that read the same backwards […]
My Haskell solution (see http://bonsaicode.wordpress.com/2009/05/22/programming-praxis-%E2%80%93-the-next-palindrome/ for a version with comments):
Lilac, my solution still applies eventhough it is inneficient.
Updated version that’s one line shorter and 50% faster:
Remco, please try nextPalindrome 9919.
;; Take 2: Efficient version
New version that works correctly for 9919:
Remco,
I’m curious. In the first version, how did 9919, or any of the smaller numbers where the second half is less than the first half, pass your test? The test looks to me like it should have worked.
They didn’t, because there was no such test. In the 0, 88…99999 list you used the second half is always greater than or equal to the first half.
The other test just recursively calls nextPalindrome, so the input number is always symmetrical, in which case my original algorithm works ok.
Since there was no test for that type of case I never noticed that bug.
@Jaime Vargas: If thermodynamics means it’s impossible for your program to be executed on certain valid inputs (because any computing device would break down due to entropy first), then I would say the solution does not apply. 10^499978 years is plenty of time for that (and that’s assuming an insanely fast computer is used).
Hey I am Happy To see this Post
“Next Palindrome Number”! which was posted on my blog!
And Thanks For Solving This!
Very Nice Collection!
ruby solution (http://codepad.org/cREcLRuP)
This is a solution in c#
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace LeapYear_Trial
{
class Program
{
public bool Palindrome(string number)
{
return number.SequenceEqual(number.Reverse());
}
static void Main(string[] args)
{
Program obj = new Program();
Console.WriteLine(“Input a number “);
int num = Convert.ToInt32(Console.ReadLine());
int nextNum = num + 1;
while(!obj.Palindrome(nextNum.ToString()))
{
nextNum += 1;
}
Console.WriteLine(“The next smallest palindrome larger than {0} is {1}”, num, nextNum);
}
}
}