Search code examples
scalaloopsiterationbreakpalindrome

Palindromes using Scala


I came across this problem from CodeChef. The problem states the following:

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.

I can define a isPalindrome method as follows:

def isPalindrome(someNumber:String):Boolean = someNumber.reverse.mkString == someNumber

The problem that I am facing is how do I loop from the initial given number and break and return the first palindrome when the integer satisfies the isPalindrome method? Also, is there a better(efficient) way to write the isPalindrome method?

It will be great to get some guidance here


Solution

  • If you have a number like 123xxx you know, that either xxx has to be below 321 - then the next palindrom is 123321.

    Or xxx is above, then the 3 can't be kept, and 124421 has to be the next one.

    Here is some code without guarantees, not very elegant, but the case of (multiple) Nines in the middle is a bit hairy (19992):

    object Palindrome extends App {
    
    def nextPalindrome (inNumber: String): String = {
      val len = inNumber.length ()
      if (len == 1 && inNumber (0) != '9') 
        "" + (inNumber.toInt + 1) else {
        val head = inNumber.substring (0, len/2)
        val tail = inNumber.reverse.substring (0, len/2)
        val h = if (head.length > 0) BigInt (head) else BigInt (0)
        val t = if (tail.length > 0) BigInt (tail) else BigInt (0)
    
        if (t < h) {
          if (len % 2 == 0) head + (head.reverse)
          else inNumber.substring (0, len/2 + 1) + (head.reverse)
        } else {
         if (len % 2 == 1) {
           val s2 = inNumber.substring (0, len/2 + 1) // 4=> 4
           val h2 = BigInt (s2) + 1  // 5 
           nextPalindrome (h2 + (List.fill (len/2) ('0').mkString)) // 5 + "" 
         } else {
           val h = BigInt (head) + 1
           h.toString + (h.toString.reverse)
         }
        }
      }
    }
    
    def check (in: String, expected: String) = {
      if (nextPalindrome (in) == expected) 
        println ("ok: " + in) else 
        println (" - fail: " + nextPalindrome (in) + " != " + expected + " for: " + in)
    }
    //
    val nums = List (("12345", "12421"), // f
      ("123456", "124421"), 
      ("54321", "54345"), 
      ("654321", "654456"), 
      ("19992", "20002"),
      ("29991", "29992"),
      ("999", "1001"),
      ("31", "33"),
      ("13", "22"),
      ("9", "11"),
      ("99", "101"),
      ("131", "141"),
      ("3", "4")
    )
    nums.foreach (n => check (n._1, n._2))
    println (nextPalindrome ("123456678901234564579898989891254392051039410809512345667890123456457989898989125439205103941080951234566789012345645798989898912543920510394108095"))
    
    }
    

    I guess it will handle the case of a one-million-digit-Int too.