Perl Weekly Challenge 288: Closest Palindrome

These are some answers to the Week 288, Task 1, of the Perl Weekly Challenge organized by Mohammad S. Anwar.

Spoiler Alert: This weekly challenge deadline is due in a few days from now (on September 29, 2024, at 23:59). This blog post provides some solutions to this challenge. Please don’t read on if you intend to complete the challenge on your own.

Task 1: Closest Palindrome

You are given a string, $str, which is an integer.

Write a script to find out the closest palindrome, not including itself. If there are more than one then return the smallest.

The closest is defined as the absolute difference minimized between two integers.

Example 1

Input: $str = "123"
Output: "121"

Example 2

Input: $str = "2"
Output: "1"

There are two closest palindrome "1" and "3". Therefore we return the smallest "1".

Example 3

Input: $str = "1400"
Output: "1441"

Example 4

Input: $str = "1001"
Output: "999"

Closest Palindrome in Raku

To find if a number is a palindrome, we simply flip it and check whether the result is equal to the original number. We start with a gap equal to 1, and check whether the original number minus the gap is a palindrome or whether the original number plus the gap is a palindrome. If any is a palindrome, we return it to the caller. If not, we continue with a gap of 2, and then 3, 4, etc.

sub closest-palindrome ($in) {
    for 1..Inf -> $i {
        return $in - $i if ($in - $i).flip eq $in - $i;
        return $in + $i if ($in + $i).flip eq $in + $i;
    }
}

my @tests = 123, 2, 1400, 1001;
for @tests -> $test {
    printf "%-6d => ", $test;
    say closest-palindrome $test;
}

This program displays the following output:

$ raku ./closest-palindrome.raku
123    => 121
2      => 1
1400   => 1441
1001   => 999

Closest Palindrome in Raku

This is a port to Perl of the above Raku program. Please see the previous section if you need further explanation. The equivalent of flip in Perl is reverse (in scalar context).

use strict;
use warnings;
use feature 'say';

sub closest_palindrome {
    my $in = shift;
    my $i = 1;
    while (1) {
        return $in - $i if reverse($in - $i) eq $in - $i;
        return $in + $i if reverse($in + $i) eq $in + $i;
        $i++;
    }
}

my @tests = (123, 2, 1400, 1001);
for my $test (@tests) {
    printf "%-6d => ", $test;
    say closest_palindrome $test;
}

This program displays the following output:

$ perl ./closest-palindrome.pl
123    => 121
2      => 1
1400   => 1441
1001   => 999

Wrapping up

The next week Perl Weekly Challenge will start soon. If you want to participate in this challenge, please check https://perlweeklychallenge.org/ and make sure you answer the challenge before 23:59 BST (British summer time) on October 6, 2024. And, please, also spread the word about the Perl Weekly Challenge if you can.

Leave a comment

About laurent_r

user-pic I am the author of the "Think Perl 6" book (O'Reilly, 2017) and I blog about the Perl 5 and Raku programming languages.