diff options
| author | Mohammad Sajid Anwar <Mohammad.Anwar@yahoo.com> | 2024-09-23 15:33:19 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-09-23 15:33:19 +0100 |
| commit | ba597cbbcd5d0702cd0304c0bf39ec8fddb75c43 (patch) | |
| tree | 48484ee6a67fbb3cb44846ae1026d957961b6611 | |
| parent | 5d153977cad3f0d33e3f3512f7e61f249e0ceee8 (diff) | |
| parent | 44618011786dfdb682af99e11b388fc2369551f5 (diff) | |
| download | perlweeklychallenge-club-ba597cbbcd5d0702cd0304c0bf39ec8fddb75c43.tar.gz perlweeklychallenge-club-ba597cbbcd5d0702cd0304c0bf39ec8fddb75c43.tar.bz2 perlweeklychallenge-club-ba597cbbcd5d0702cd0304c0bf39ec8fddb75c43.zip | |
Merge pull request #10895 from LubosKolouch/master
feat(challenge-288/lubos-kolouch/perl,python/): Challenge 288 LK Perl Python
| -rw-r--r-- | challenge-288/lubos-kolouch/perl/ch-1.pl | 83 | ||||
| -rw-r--r-- | challenge-288/lubos-kolouch/perl/ch-2.pl | 99 | ||||
| -rw-r--r-- | challenge-288/lubos-kolouch/python/ch-1.py | 80 | ||||
| -rw-r--r-- | challenge-288/lubos-kolouch/python/ch-2.py | 91 |
4 files changed, 353 insertions, 0 deletions
diff --git a/challenge-288/lubos-kolouch/perl/ch-1.pl b/challenge-288/lubos-kolouch/perl/ch-1.pl new file mode 100644 index 0000000000..55604105ec --- /dev/null +++ b/challenge-288/lubos-kolouch/perl/ch-1.pl @@ -0,0 +1,83 @@ +#!/usr/bin/perl +use strict; +use warnings; +use Test::More tests => 4; + +=pod + +=head1 DESCRIPTION + +This script finds the closest palindrome integer to a given integer string, +excluding the integer itself. If there are multiple palindromes with the same +minimal absolute difference, it returns the smallest one. + +=head1 FUNCTIONS + +=head2 closest_palindrome($str) + +Given a string representing an integer, returns the closest palindrome as per +the problem definition. + +=over 4 + +=item * C<$str> - The input integer as a string. + +=back + +Returns the closest palindrome integer as a string. + +=cut + +sub closest_palindrome { + my ($n_str) = @_; + my $n = int($n_str); + my $len = length($n_str); + my $is_even = $len % 2 == 0; + my $mid = int($len / 2); + + # Obtain the left part of the number + my $left_len = $is_even ? $mid : $mid + 1; + my $left = substr($n_str, 0, $left_len); + my @candidates; + + foreach my $i (-1, 0, 1) { + my $new_left = int($left) + $i; + next if $new_left < 0; + my $new_left_str = "$new_left"; + + my $palindrome; + if ($is_even) { + $palindrome = $new_left_str . reverse($new_left_str); + } else { + $palindrome = $new_left_str . reverse(substr($new_left_str, 0, -1)); + } + push @candidates, $palindrome; + } + + # Edge cases + push @candidates, ('9' x ($len - 1)) if $len > 1; + push @candidates, '1' . ('0' x ($len - 1)) . '1'; + + # Remove the original number from candidates + @candidates = grep { $_ ne $n_str } @candidates; + + # Find the closest palindrome + my $min_diff = undef; + my $closest_palindrome = undef; + foreach my $candidate (@candidates) { + my $diff = abs(int($candidate) - $n); + if (!defined $min_diff || $diff < $min_diff || ($diff == $min_diff && int($candidate) < int($closest_palindrome))) { + $min_diff = $diff; + $closest_palindrome = $candidate; + } + } + return $closest_palindrome; +} + +# Unit Tests +is(closest_palindrome("123"), "121", 'Example 1'); +is(closest_palindrome("2"), "1", 'Example 2'); +is(closest_palindrome("1400"), "1441", 'Example 3'); +is(closest_palindrome("1001"), "999", 'Example 4'); + +done_testing(); diff --git a/challenge-288/lubos-kolouch/perl/ch-2.pl b/challenge-288/lubos-kolouch/perl/ch-2.pl new file mode 100644 index 0000000000..4bb8e24f16 --- /dev/null +++ b/challenge-288/lubos-kolouch/perl/ch-2.pl @@ -0,0 +1,99 @@ +#!/usr/bin/perl +use strict; +use warnings; +use Test::More tests => 3; + +=pod + +=head1 DESCRIPTION + +This script finds the size of the largest contiguous block in a given rectangular matrix of 'x' and 'o'. + +A contiguous block consists of elements containing the same symbol which share an edge (not just a corner) with other elements in the block, and where there is a path between any two of these elements that crosses only those shared edges. + +=head1 FUNCTIONS + +=head2 largest_contiguous_block(\@matrix) + +Given a reference to a 2D array representing the matrix, returns the size of the largest contiguous block. + +=over 4 + +=item * C<\@matrix> - Reference to a 2D array of 'x' and 'o'. + +=back + +Returns the size of the largest contiguous block as an integer. + +=back + +=cut + +sub largest_contiguous_block { + my ($matrix_ref) = @_; + my @matrix = @$matrix_ref; + my $rows = scalar @matrix; + my $cols = scalar @{ $matrix[0] }; + my @visited = map { [(0) x $cols] } (0 .. $rows - 1); + my $max_block_size = 0; + + for my $i (0 .. $rows - 1) { + for my $j (0 .. $cols - 1) { + if (!$visited[$i][$j]) { + my $block_size = dfs($matrix_ref, \@visited, $i, $j, $matrix[$i][$j]); + $max_block_size = $block_size if $block_size > $max_block_size; + } + } + } + + return $max_block_size; +} + +sub dfs { + my ($matrix_ref, $visited_ref, $i, $j, $symbol) = @_; + my @matrix = @$matrix_ref; + my $rows = scalar @matrix; + my $cols = scalar @{ $matrix[0] }; + + return 0 if $i < 0 || $i >= $rows || $j < 0 || $j >= $cols; + return 0 if $visited_ref->[$i][$j]; + return 0 if $matrix[$i][$j] ne $symbol; + + $visited_ref->[$i][$j] = 1; + my $size = 1; + + # Explore neighbors (up, down, left, right) + $size += dfs($matrix_ref, $visited_ref, $i - 1, $j, $symbol); + $size += dfs($matrix_ref, $visited_ref, $i + 1, $j, $symbol); + $size += dfs($matrix_ref, $visited_ref, $i, $j - 1, $symbol); + $size += dfs($matrix_ref, $visited_ref, $i, $j + 1, $symbol); + + return $size; +} + +# Unit Tests +my $matrix1 = [ + ['x', 'x', 'x', 'x', 'o'], + ['x', 'o', 'o', 'o', 'o'], + ['x', 'o', 'o', 'o', 'o'], + ['x', 'x', 'x', 'o', 'o'], +]; +is(largest_contiguous_block($matrix1), 11, 'Example 1'); + +my $matrix2 = [ + ['x', 'x', 'x', 'x', 'x'], + ['x', 'o', 'o', 'o', 'o'], + ['x', 'x', 'x', 'x', 'o'], + ['x', 'o', 'o', 'o', 'o'], +]; +is(largest_contiguous_block($matrix2), 11, 'Example 2'); + +my $matrix3 = [ + ['x', 'x', 'x', 'o', 'o'], + ['o', 'o', 'o', 'x', 'x'], + ['o', 'x', 'x', 'o', 'o'], + ['o', 'o', 'o', 'x', 'x'], +]; +is(largest_contiguous_block($matrix3), 7, 'Example 3'); + +done_testing(); diff --git a/challenge-288/lubos-kolouch/python/ch-1.py b/challenge-288/lubos-kolouch/python/ch-1.py new file mode 100644 index 0000000000..c9331a2058 --- /dev/null +++ b/challenge-288/lubos-kolouch/python/ch-1.py @@ -0,0 +1,80 @@ +import unittest + + +def closest_palindrome(n_str: str) -> str: + """ + Finds the closest palindrome to the given integer string, excluding itself. + If multiple palindromes have the same minimal absolute difference, returns the smallest one. + + Args: + n_str (str): The input integer as a string. + + Returns: + str: The closest palindrome integer as a string. + """ + n = int(n_str) + length = len(n_str) + is_even = length % 2 == 0 + mid = length // 2 + left_len = mid if is_even else mid + 1 + left = n_str[:left_len] + candidates = set() + + for diff in (-1, 0, 1): + new_left = str(int(left) + diff) + if len(new_left) != left_len and diff != 0: + continue + if is_even: + pal = new_left + new_left[::-1] + else: + pal = new_left + new_left[:-1][::-1] + candidates.add(pal) + + # Edge cases + candidates.add("9" * (length - 1)) + candidates.add("1" + ("0" * (length - 1)) + "1") + + candidates.discard(n_str) + + min_diff = None + closest_pal = "" + for cand in candidates: + if cand == "": + continue + diff = abs(int(cand) - n) + if diff == 0: + continue + if ( + min_diff is None + or diff < min_diff + or (diff == min_diff and int(cand) < int(closest_pal)) + ): + min_diff = diff + closest_pal = cand + + return closest_pal + + +# Unit Tests +class TestClosestPalindrome(unittest.TestCase): + def test_example1(self): + self.assertEqual(closest_palindrome("123"), "121", "Example 1") + + def test_example2(self): + self.assertEqual(closest_palindrome("2"), "1", "Example 2") + + def test_example3(self): + self.assertEqual(closest_palindrome("1400"), "1441", "Example 3") + + def test_example4(self): + self.assertEqual(closest_palindrome("1001"), "999", "Example 4") + + def test_large_number(self): + self.assertEqual(closest_palindrome("999"), "1001", "Large Number") + + def test_all_nines(self): + self.assertEqual(closest_palindrome("9999"), "10001", "All Nines") + + +if __name__ == "__main__": + unittest.main() diff --git a/challenge-288/lubos-kolouch/python/ch-2.py b/challenge-288/lubos-kolouch/python/ch-2.py new file mode 100644 index 0000000000..6c1a36e609 --- /dev/null +++ b/challenge-288/lubos-kolouch/python/ch-2.py @@ -0,0 +1,91 @@ +import unittest +from typing import List + + +def largest_contiguous_block(matrix: list[list[str]]) -> int: + """ + Finds the size of the largest contiguous block in a given matrix of 'x' and 'o'. + + A contiguous block consists of elements containing the same symbol which share + an edge (not just a corner) with other elements in the block, and where there + is a path between any two of these elements that crosses only those shared edges. + + Args: + matrix (List[List[str]]): The input matrix of 'x' and 'o'. + + Returns: + int: The size of the largest contiguous block. + """ + if not matrix or not matrix[0]: + return 0 + + rows = len(matrix) + cols = len(matrix[0]) + visited = [[False] * cols for _ in range(rows)] + max_block_size = 0 + + def dfs(i: int, j: int, symbol: str) -> int: + if i < 0 or i >= rows or j < 0 or j >= cols: + return 0 + if visited[i][j]: + return 0 + if matrix[i][j] != symbol: + return 0 + + visited[i][j] = True + size = 1 + # Explore neighbors (up, down, left, right) + size += dfs(i - 1, j, symbol) + size += dfs(i + 1, j, symbol) + size += dfs(i, j - 1, symbol) + size += dfs(i, j + 1, symbol) + return size + + for i in range(rows): + for j in range(cols): + if not visited[i][j]: + block_size = dfs(i, j, matrix[i][j]) + max_block_size = max(max_block_size, block_size) + + return max_block_size + + +# Unit Tests +class TestLargestContiguousBlock(unittest.TestCase): + def test_example1(self): + matrix = [ + ["x", "x", "x", "x", "o"], + ["x", "o", "o", "o", "o"], + ["x", "o", "o", "o", "o"], + ["x", "x", "x", "o", "o"], + ] + self.assertEqual(largest_contiguous_block(matrix), 11, "Example 1") + + def test_example2(self): + matrix = [ + ["x", "x", "x", "x", "x"], + ["x", "o", "o", "o", "o"], + ["x", "x", "x", "x", "o"], + ["x", "o", "o", "o", "o"], + ] + self.assertEqual(largest_contiguous_block(matrix), 11, "Example 2") + + def test_example3(self): + matrix = [ + ["x", "x", "x", "o", "o"], + ["o", "o", "o", "x", "x"], + ["o", "x", "x", "o", "o"], + ["o", "o", "o", "x", "x"], + ] + self.assertEqual(largest_contiguous_block(matrix), 7, "Example 3") + + def test_empty_matrix(self): + self.assertEqual(largest_contiguous_block([]), 0, "Empty Matrix") + + def test_single_element(self): + matrix = [["x"]] + self.assertEqual(largest_contiguous_block(matrix), 1, "Single Element") + + +if __name__ == "__main__": + unittest.main() |
