diff options
| author | Myoungjin JEON <jeongoon@gmail.com> | 2020-08-28 22:54:33 +1000 |
|---|---|---|
| committer | Myoungjin JEON <jeongoon@gmail.com> | 2020-08-28 22:54:33 +1000 |
| commit | 113c25e7c3e065fb32fbcae91cb1c7444db89c1f (patch) | |
| tree | 4926baeb6d4e95e9ceceb13734246154dd570965 /challenge-075 | |
| parent | f270b932857463ce2a02308887394ac34a032578 (diff) | |
| parent | 15ac63c0f3554fc95fbeb05fa7504a205ab76142 (diff) | |
| download | perlweeklychallenge-club-113c25e7c3e065fb32fbcae91cb1c7444db89c1f.tar.gz perlweeklychallenge-club-113c25e7c3e065fb32fbcae91cb1c7444db89c1f.tar.bz2 perlweeklychallenge-club-113c25e7c3e065fb32fbcae91cb1c7444db89c1f.zip | |
Merge remote-tracking branch 'upstream/master' into ch-075
Diffstat (limited to 'challenge-075')
20 files changed, 1067 insertions, 57 deletions
diff --git a/challenge-075/alexander-pankoff/README b/challenge-075/alexander-pankoff/README new file mode 100644 index 0000000000..41f67807ac --- /dev/null +++ b/challenge-075/alexander-pankoff/README @@ -0,0 +1 @@ +Solution by Alexander Pankoff diff --git a/challenge-075/alexander-pankoff/perl/ch-1.pl b/challenge-075/alexander-pankoff/perl/ch-1.pl new file mode 100755 index 0000000000..ad37e76630 --- /dev/null +++ b/challenge-075/alexander-pankoff/perl/ch-1.pl @@ -0,0 +1,86 @@ +#!/usr/bin/env perl + +use strict; +use warnings; +use feature qw(signatures say); +no warnings qw(experimental::signatures experimental::smartmatch); + +use List::Util qw(any sum0); +use Scalar::Util qw(looks_like_number); + +# You are given an array of positive numbers @A. +# +# Write a script to find the larget rectangle histogram created by the given array. +# BONUS: Try to print the histogram as shown in the example, if possible. + +my ( $S, @C ) = @ARGV; + +$S //= 6; + +@C = ( 1, 2, 4 ) unless @C; + +if ( ( any { !looks_like_number( $_ ) } ( $S, @C ) ) + || ( any { $_ < 1 } @C ) ) +{ + usage(); + exit 1; +} + +my @possible_combinations = possible_combinations( \@C, $S ); + +say scalar @possible_combinations; + +exit 0 unless $ENV{DEBUG}; + +for my $combination ( @possible_combinations ) { + say "(" . join( ', ', @$combination ) . ")"; +} + +exit 0; + +sub possible_combinations ( $coins, $sum, $cur = [] ) { + my $current_sum = sum0 @{$cur}; + + return $cur if $current_sum == $sum; + die "invalid" if $current_sum > $sum; + + my @solutions; + for my $coin ( @$coins ) { + eval { + my @sub_solutions = possible_combinations( $coins, $sum, [ @$cur, $coin ] ); + push @solutions, map { + [ sort { $a <=> $b } @$_ ] + } @sub_solutions; + }; + + die $@ if $@ and $@ !~ /invalid/; + } + + return unique_combinations( @solutions ); +} + +sub unique_combinations(@list) { + my @out; + + for my $item ( @list ) { + my $found = 0; + for my $check ( @out ) { + if ( @$check ~~ @$item ) { + $found = 1; + last; + } + } + push @out, $item unless $found; + } + + return @out; +} + +sub usage() { + say <<END; +$0 <SUM> [COINS] + + <SUM> the sum that should be created + [COINS] the set of coins available +END +} diff --git a/challenge-075/alexander-pankoff/perl/ch-2.pl b/challenge-075/alexander-pankoff/perl/ch-2.pl new file mode 100755 index 0000000000..3bd029a638 --- /dev/null +++ b/challenge-075/alexander-pankoff/perl/ch-2.pl @@ -0,0 +1,64 @@ +#!/usr/bin/env perl + +use strict; +use warnings; +use feature qw(signatures say); +no warnings qw(experimental::signatures); + +use Scalar::Util qw(looks_like_number); +use List::Util qw(any min max); + +# You are given an array of positive numbers @A. +# +# Write a script to find the larget rectangle histogram created by the given array. +# BONUS: Try to print the histogram as shown in the example, if possible. + +my ( @A ) = @ARGV; + +@A = ( 2, 1, 4, 5, 3, 7 ) unless @A; + +if ( any { !looks_like_number( $_ ) || $_ < 0 } ( @A ) ) { + usage(); + exit 1; +} + +print_histogram( @A ); + +say largest_rectangle( @A ); + +exit 0; + +sub largest_rectangle(@cols) { + return 0 unless @cols; + + max( + rectangle_size( @cols ), + largest_rectangle( @cols[ 1 .. $#cols ] ), + largest_rectangle( @cols[ 0 .. ( $#cols - 1 ) ] ) + ); +} + +sub rectangle_size(@cols) { + return scalar @cols * min @cols; +} + +sub print_histogram(@cols) { + my $height = max @cols; + + while ( $height ) { + say join( ' ', $height, map { $_ >= $height ? '#' : ' ' } @cols ); + $height--; + } + + say join( ' ', map { '_' } ( 0 .. @cols ) ); + say join( ' ', ' ', @cols ); +} + +sub usage() { + say <<END +$0 [A] + + [A] An array of positive integers +END +} + diff --git a/challenge-075/dave-jacoby/perl/ch-1.pl b/challenge-075/dave-jacoby/perl/ch-1.pl new file mode 100755 index 0000000000..670ed4c751 --- /dev/null +++ b/challenge-075/dave-jacoby/perl/ch-1.pl @@ -0,0 +1,52 @@ +#!/usr/bin/env perl + +use strict; +use warnings; +use feature qw{ say signatures state }; +no warnings qw{ experimental }; + +use List::Util qw{ sum }; +use JSON; +my $json = JSON->new->pretty->canonical; + +my @C = ( 1, 2, 4 ); +my $S = 6; +my @output = resort( coins_sum( [], $S, \@C ) ); + +make_output( $S, @output ); + +sub coins_sum ( $input, $sum, $coins ) { + my @output; + for my $c ( $coins->@* ) { + my $input2->@* = $input->@*; + push $input2->@*, $c; + $input2->@* = sort $input2->@*; + my $input3 = join ',', sort $input2->@*; + my $sum2 = $sum - $c; + if ( $sum2 > 0 ) { + push @output, coins_sum( $input2, $sum2, $coins ); + } + elsif ( $sum2 == 0 ) { + push @output, $input2; + } + } + return wantarray ? @output : \@output; +} + +sub resort ( @array ) { + my $done = {}; + return grep { !$done->{$_}++ } + map { join ',', sort $_->@* } @array; +} + +sub make_output ( $sum, @output ) { + my $c = scalar @output; + my @letters = 'a'..'z'; + + say qq{ There are 6 possible ways to make sum $sum }; + for my $i ( 0 .. $#output ) { + my $l = $letters[$i]; + say qq{ $letters[$i]) $output[$i] }; + } + +} diff --git a/challenge-075/dave-jacoby/perl/ch-2.pl b/challenge-075/dave-jacoby/perl/ch-2.pl new file mode 100755 index 0000000000..68d494a53d --- /dev/null +++ b/challenge-075/dave-jacoby/perl/ch-2.pl @@ -0,0 +1,94 @@ +#!/usr/bin/env perl + +use strict; +use warnings; +use feature qw{ say signatures state }; +no warnings qw{ experimental }; + +use List::Util qw{ max }; +use JSON; +my $json = JSON->new->pretty->canonical; + +{ + my @A = ( 2, 1, 4, 5, 3, 7 ); + my @histogram = make_histogram(@A); + find_largest_rectangle(@histogram); +} +{ + my @A = ( 3, 2, 3, 5, 7, 5 ); + my @histogram = make_histogram(@A); + find_largest_rectangle(@histogram); +} + +exit; + +sub make_histogram ( @input ) { + my $max = max @input; + my @output; + + for my $i ( 0 .. scalar @input ) { + my $local = []; + my $n = $input[$i]; + next unless $n; + for my $j ( 1 .. $max ) { + push $local->@*, $j <= $n ? '#' : ' '; + } + push @output, $local; + } + + return @output; +} + +sub display_histogram( @histogram ) { + my $max_x = scalar @histogram - 1; + my $max_y = scalar $histogram[0]->@* - 1; + for my $y ( reverse 0 .. $max_y ) { + for my $x ( 0 .. $max_x ) { + my $c = $histogram[$x][$y]; + print $c . ' '; + } + say ''; + } + say ''; +} + +sub find_largest_rectangle( @histogram ) { + my $max_x = scalar @histogram - 1; + my $max_y = scalar $histogram[0]->@* - 1; + + my @output; + + for my $x1 ( 0 .. $max_x - 1 ) { + for my $x2 ( $x1 + 1 .. $max_x ) { + for my $y1 ( 0 .. $max_y ) { + for my $y2 ( $y1 .. $max_y ) { + + my ( $c1, $c2 ) = ( 0, 0 ); + my @v; + for my $x ( $x1 .. $x2 ) { + for my $y ( $y1 .. $y2 ) { + my $v = $histogram[$x][$y]; + push @v, $v; + $c1++; + $c2++ if $v eq '#'; + } + } + + next if $c1 != $c2; + push @output, [ $c1, $x1, $y1, $x2, $y2 ]; + } + } + } + } + + @output = sort { $b->[0] <=> $a->[0] } @output; + my ( $c1, $x1, $y1, $x2, $y2 ) = $output[0]->@*; + my $columns = join ',', map { $_ + 1 } $x1 .. $x2; + my $x = 1 + $x2 - $x1; + my $y = 1 + $y2 - $y1; + + + display_histogram(@histogram); + say qq{the largest rectangle ($x x $y) is formed by columns ($columns)}; + say ''; +} diff --git a/challenge-075/e-choroba/perl/ch-1.pl b/challenge-075/e-choroba/perl/ch-1.pl new file mode 100755 index 0000000000..9906213aea --- /dev/null +++ b/challenge-075/e-choroba/perl/ch-1.pl @@ -0,0 +1,34 @@ +#! /usr/bin/perl +use warnings; +use strict; + +# Visible impact for tests #2 and #3. +use Memoize; +memoize('_coins_sum'); + +sub _coins_sum { + my ($sum, @coins) = @_; + my @r; + for my $coin (@coins) { + next if $sum < $coin; + push @r, $sum == $coin + ? [$coin] + : map [ $coin, @$_ ], + grep $_->[0] >= $coin, + do { no warnings 'recursion'; + _coins_sum($sum - $coin, @coins) }; + } + return @r +} + +sub coins_sum { + my ($sum, @coins) = @_; + my @r = _coins_sum($sum, @coins); + return scalar @r +} + +use Test::More tests => 3; + +is coins_sum(6, 1, 2, 4), 6; +is coins_sum(24, 1, 2, 4), 49; +is coins_sum(80, 2, 7), 6; diff --git a/challenge-075/e-choroba/perl/ch-2.pl b/challenge-075/e-choroba/perl/ch-2.pl new file mode 100755 index 0000000000..21e90d6385 --- /dev/null +++ b/challenge-075/e-choroba/perl/ch-2.pl @@ -0,0 +1,90 @@ +#! /usr/bin/perl +use warnings; +use strict; +use feature qw{ say }; +use Syntax::Construct qw{ // }; + +use List::Util qw{ max }; + +sub draw_histogram { + my @columns = @_; + my $max = max(@columns); + my $max_length = length $max; + for my $y (reverse 1 .. $max) { + printf "%${max_length}d ", $y; + say join ' ', map { + sprintf "%${max_length}s", $columns[$_ - 1] >= $y ? '#' : ' ' + } 1 .. @columns; + } + say join ' ', ('_' x $max_length) x (1 + @columns); + printf "%${max_length}s ", ""; + say join ' ', map sprintf("%${max_length}d", $_), @columns; +} + +sub _pop { + my ($max, $smallest, $columns, $column) = @_; + my $s = pop @$smallest; + my $area = $columns->[$s] * ($column - ($smallest->[-1] // -1) - 1); + $$max = $area if $area > $$max; +} + +sub largest_rectangle { + my @columns = @_; + my @smallest; + my $max = 0; + my $column = 0; + while ($column <= $#columns) { + if (! @smallest || $columns[$column] > $columns[ $smallest[-1] ]) { + push @smallest, $column++; + } else { + _pop(\$max, \@smallest, \@columns, $column); + } + } + _pop(\$max, \@smallest, \@columns, $column) while @smallest; + return $max +} + +use Test::More tests => 5; + +{ + open my $stdout, '>', \ my $out; + select $stdout; + draw_histogram(2, 1, 4, 5, 3, 7); + is $out, << '__STDOUT__', 'Print Example 1'; +7 # +6 # +5 # # +4 # # # +3 # # # # +2 # # # # # +1 # # # # # # +_ _ _ _ _ _ _ + 2 1 4 5 3 7 +__STDOUT__ +} + +{ + open my $stdout, '>', \ my $out; + select $stdout; + draw_histogram(2, 10); + is $out, << '__STDOUT__', 'Longer numbers'; +10 # + 9 # + 8 # + 7 # + 6 # + 5 # + 4 # + 3 # + 2 # # + 1 # # +__ __ __ + 2 10 +__STDOUT__ +} + +is largest_rectangle(2, 1, 4, 5, 3, 7), 12, 'Example 1'; +is largest_rectangle(3, 2, 3, 5, 7, 5), 15, 'Example 2'; + +# https://www.geeksforgeeks.org/largest-rectangle-under-histogram/ +is largest_rectangle(6, 2, 5, 4, 5, 1, 6), 12, 'Sumit Ghosh'; diff --git a/challenge-075/jason-messer/raku/ch-1.p6 b/challenge-075/jason-messer/raku/ch-1.p6 new file mode 100644 index 0000000000..003931441e --- /dev/null +++ b/challenge-075/jason-messer/raku/ch-1.p6 @@ -0,0 +1,14 @@ +#! /usr/bin/env rakudo + +sub coin-combinations( Int :$sum, :@coins where .all > 0 ) { + my @combinations = 1, |(0 xx $sum); + + for @coins -> $coin { + loop (my $i = $coin; $i < @combinations.elems; ++$i) { + @combinations[$i] += @combinations[$i - $coin]; + } + } + return @combinations.tail; +} + +say coin-combinations :sum(6), :coins([1, 2, 4]); diff --git a/challenge-075/jason-messer/raku/ch-2.p6 b/challenge-075/jason-messer/raku/ch-2.p6 new file mode 100644 index 0000000000..c466853fab --- /dev/null +++ b/challenge-075/jason-messer/raku/ch-2.p6 @@ -0,0 +1,38 @@ +#! /usr/bin/env rakudo + +sub largest-rectangle( @a ) { + my @r = gather loop (my $i = 0; $i < @a.elems; ++$i) { + + my $height = @a[$i]; + my $width = 1; + loop (my $back = $i - 1; $back >= 0; --$back) { + last if @a[$back] < $height; + $width++; + } + loop (my $forward = $i + 1; $forward < @a.elems; ++$forward) { + last if @a[$forward] < $height; + $width++; + } + take $width * $height; + } + return max(@r); +} + +sub print-histogram( @a ) { + loop (my $height = max(@a); $height > 0; --$height) { + my Str @parts = $height.Str xx 1; + @parts.append: @a.map( {$_ >= $height ?? '#' !! ' '} ); + say @parts.join: ' '; + } + say "- " x @a.elems + 1; + say ' ', @a.join: ' '; +} + +my @A = [2, 1, 4, 5, 3, 7]; +my @B = [3, 2, 3, 5, 7, 5]; + +print-histogram(@A); +say "area: ", largest-rectangle(@A); + +print-histogram(@B); +say "area: ", largest-rectangle(@B); diff --git a/challenge-075/jo-37/perl/ch-1.pl b/challenge-075/jo-37/perl/ch-1.pl new file mode 100755 index 0000000000..2c75a7fc10 --- /dev/null +++ b/challenge-075/jo-37/perl/ch-1.pl @@ -0,0 +1,39 @@ +#!/usr/bin/perl + +use Test2::V0; +use List::Util qw(any min); + +# Assemble given sum (1st arg) from a set of coins having values as +# specified in the remaining arguments. +sub assemble; +sub assemble { + my ($sum, @coins) = @_; + + # There is no solution if the sum is less than the smallest coin. + return if $sum < min @coins; + + # If a coin matches the given sum, this gives one (non-recursive) + # assembly. + ((any {$sum == $_} @coins) ? [$sum] : (), + # Try each coin for further assemblies. + map { + my $coin = $_; + # Reduce the sum by the selected coin and combine that one with + # all possible assemblies of the reduced sum using solely coins + # that are not smaller than the selected. + map [$coin, @$_], assemble $sum - $coin, grep $_ >= $coin, @coins; + } @coins); +} + +is [assemble 6, 1, 2, 4], + bag { + item([1, 1, 1, 1, 1, 1]), + item([1, 1, 1, 1, 2]), + item([1, 1, 2, 2]), + item([1, 1, 4]), + item([2, 2, 2]), + item([2, 4]), + end() + }, 'example from challenge'; + +done_testing; diff --git a/challenge-075/jo-37/perl/ch-2.pl b/challenge-075/jo-37/perl/ch-2.pl new file mode 100755 index 0000000000..251539c6ae --- /dev/null +++ b/challenge-075/jo-37/perl/ch-2.pl @@ -0,0 +1,124 @@ +#!/usr/bin/perl + + +# A tailor-made class for this task. +package Rectangle; + +use strict; +use warnings; +use List::Util qw(min); +use overload + '<=>' => \&cmp_rect, # compare by size + '.=' => \&position, # set position + '""' => \&show; # stringify + +# Create a new rectangle over the full length of +# the given (partial) histogram and with maximum height. +sub new { + my $class = shift; + + bless {height => min(@_) // 0, + length => scalar @_, + position => -1}, $class; +} + +# Compare two rectangles by size. +sub cmp_rect { + my ($self, $other) = @_; + + $self->{length} * $self->{height} <=> $other->{length} * $other->{height}; +} + +# Set (end) position. +sub position { + my ($self, $pos) = @_; + + $self->{position} = $pos; + $self; +} + +# String representation. +sub show { + my $self = shift; + + sprintf "size=%d, length=%d, position=%d, height=%d", + $self->{length} * $self->{height}, $self->{length}, + $self->{position}, $self->{height}; +} + +# Check if point is contained in rectangle. +sub contains { + my ($self, $ix, $height) = @_; + + $ix >= $self->{position} - $self->{length} + 1 && + $ix <= $self->{position} && $height <= $self->{height}; +} + +package main; + +use strict; +use warnings; +use List::Util qw(max reduce); + +# Find the largest rectangle inside a histogram. +# The Rectangle constructor, comparator and assignment operator +# are specifically designed to offer a terse implementation here. +sub max_rect { + + # Slide over all elements seeking for the maximum rectangle + reduce { + my $pos = $b; + # Slide over all windows ending at the selected position. + reduce { + # Get the maximum rectangle over the full window length. + my $rect = Rectangle->new(@_[$b .. $pos]); + # If the new rectangle is larger than the current maximum, + # set the position and use it as the new maximum. + $rect > $a ? $rect .= $pos : $a; + } $a, 0 .. $b; + } Rectangle->new, 0 .. $#_; +} + +# Create the histogram row data at the given height: +# - empty, if height is above the value +# - asterisk, if the point is inside the maximum rectangle +# - hash otherwise. +sub hist_chars { + my ($max, $height) = (shift, shift); + + map $_[$_] >= $height ? + $max->contains($_, $height) ? + '*' : '#' : '', 0 .. $#_; +} + +# Generate a format string. Produces $size + 1 items of equal +# length $len that are separated by one blank. The first item has +# conversion $first, the rest have conversion $rest. +sub gen_fmt ($$$$) { + my ($len, $first, $rest, $size) = @_; + + "%${len}${first}" . " %${len}${rest}" x $size . "\n"; +} + +# Print the histogram. +sub print_hist { + my $max = shift; + + my $height = max @_; + my $len = length $height; + + my $fmt = gen_fmt $len, 'd', 's', @_; + do { + printf $fmt, $height, hist_chars $max, $height, @_ + } while --$height; + printf gen_fmt($len, 's', 's', @_), ('-') x (@_ + 1); + printf gen_fmt($len, 's', 'd', @_), '', @_; +} + +# main + +for my $hist ([2, 1, 4, 5, 3, 7], [3, 2, 3, 5, 7, 5, 2]) { + my $max = max_rect @$hist; + print_hist $max, @$hist; + print "max rectangle: $max\n\n"; +} diff --git a/challenge-075/lubos-kolouch/perl/ch-1.pl b/challenge-075/lubos-kolouch/perl/ch-1.pl new file mode 100644 index 0000000000..756cba3ebf --- /dev/null +++ b/challenge-075/lubos-kolouch/perl/ch-1.pl @@ -0,0 +1,27 @@ +#!/usr/bin/env perl +use strict; +use warnings; +# Perl weekly challenge 075 Task 1 - Coins sum + + +sub count { + + my ($coins, $target_sum) = @_; + + my @ways = (0) x $target_sum; + $ways[0] = 1; + + for my $coin_pos (0..scalar @$coins - 1) { + for my $j (0..$target_sum) { + $ways[$j] += $ways[$j - $coins->[$coin_pos]] if $coins->[$coin_pos] <= $j; + } + } + + return $ways[$target_sum]; +} + +use Test::More; + +is(count([1, 2, 4], 6), 6, 'Test case 1, 2, 4 and 6'); +is(count([1, 5, 10], 12), 4, 'Test case 1, 5, 10 and 12'); +done_testing; diff --git a/challenge-075/lubos-kolouch/python/ch-1.py b/challenge-075/lubos-kolouch/python/ch-1.py new file mode 100644 index 0000000000..c706f7f5a0 --- /dev/null +++ b/challenge-075/lubos-kolouch/python/ch-1.py @@ -0,0 +1,21 @@ +#!/usr/bin/env python +""" Perl weekly challenge 075 Task 1 - Coins sum """ + + +def count(coins, target_sum): + """ count the ways we can sum coins """ + + ways = [0] * (target_sum + 1) + + ways[0] = 1 + + for value in coins: + for j, _ in enumerate(ways): + if value <= j: + ways[j] += ways[j - value] + + return ways[target_sum] + + +assert count([1, 2, 4], 6) == 6 +assert count([1, 5, 10], 12) == 4 diff --git a/challenge-075/mohammad-anwar/blog1.txt b/challenge-075/mohammad-anwar/blog1.txt new file mode 100644 index 0000000000..24c9c488d7 --- /dev/null +++ b/challenge-075/mohammad-anwar/blog1.txt @@ -0,0 +1 @@ +https://www.youtube.com/watch?v=DQr7xHJYZ5I diff --git a/challenge-075/mohammad-anwar/perl/ch-2.pl b/challenge-075/mohammad-anwar/perl/ch-2.pl index 7749fa9364..8e962979ad 100755 --- a/challenge-075/mohammad-anwar/perl/ch-2.pl +++ b/challenge-075/mohammad-anwar/perl/ch-2.pl @@ -3,62 +3,107 @@ # # Perl Weekly Challenge - 075 # -# Task #1: Coins Sum +# Task #2: Largest Rectangle Histogram # # https://perlweeklychallenge.org/blog/perl-weekly-challenge-075 # use strict; use warnings; +use List::Util qw(min max); -my $COINS = $ARGV[0] || "1, 2, 4"; -my $SUM = $ARGV[1] || 6; +my $L = $ARGV[0] || "2, 1, 4, 5, 3, 7"; -print "Possible ways to achieve the target: ", - coins_sum(prepare($COINS), $SUM), "\n"; +my $list = prepare($L); +print chart($list), "\n\n"; +print "Largest Rectangle Histogram: ", largest_rectangle_histogram($list), "\n"; # # # METHODS -sub coins_sum { - my ($coins, $sum) = @_; +sub largest_rectangle_histogram { + my ($list) = @_; - my $size = $#$coins; - return 0 if ($size == -1 || $sum <= 0); + my $i = 0; + my $max = 0; + foreach my $n (@$list) { - my $matrix; + my ($left, $right) = (0, 0); + $left = go_left($i, $list) if ($i > 0); + $right = go_right($i, $list) if ($i <= $#$list); - # Sum of 0 can be achieved in one possible way. - $matrix->[$_][0] = 1 for (0 .. $size+1); + my @heights = (@$list)[$i - $left .. $i + $right]; + my $size = min(@heights) * @heights; + $max = $size if ($size > $max); - foreach my $i (0 .. $size) { + $i++; + } - foreach my $j (1 .. $sum) { + return $max; +} - my $include_current = 0; - my $exclude_current = 0; +sub go_left { + my ($i, $list) = @_; - if ($coins->[$i] <= $j) { - $include_current = $matrix->[$i][$j - $coins->[$i]]; - } + my $c = $list->[$i]; + my $j = 0; + while ($i > 0) { + $i--; + last if ($list->[$i] < $c); + $j++; + } - if ($i > 0) { - $exclude_current = $matrix->[$i - 1][$j]; - } + return $j; +} + +sub go_right { + my ($i, $list) = @_; - $matrix->[$i][$j] = $include_current + $exclude_current; + my $c = $list->[$i]; + my $j = 0; + while ($i < $#$list) { + $i++; + last if ($list->[$i] < $c); + $j++; + } + + return $j; +} + +sub chart { + my ($list) = @_; + + my $max = max(@$list); + my $chart = []; + my $row = 1; + foreach (1..$max) { + my $data = ""; + foreach my $i (0..$#$list) { + if ($row <= $list->[$i]) { + $data .= " #"; + } + else { + $data .= " "; + } } + $row++; + push @$chart, sprintf("%d%s", $_, $data); } - return $matrix->[$size][$sum]; + my ($histogram, $line, $size) = ("", "", " "); + $histogram = join "\n", (reverse @$chart); + $line .= "_ " for (0..$#$list + 1); + $size .= join " ", @$list; + + return join "\n", $histogram, $line, $size; } sub prepare { - my ($coins) = @_; + my ($list) = @_; - if (defined $coins) { - $coins =~ s/\s//g; - return [ split /\,/, $coins ]; + if (defined $list) { + $list =~ s/\s//g; + return [ split /\,/, $list ]; } } diff --git a/challenge-075/mohammad-anwar/perl/ch-2.t b/challenge-075/mohammad-anwar/perl/ch-2.t index c2d32443b5..51ba0dec90 100755 --- a/challenge-075/mohammad-anwar/perl/ch-2.t +++ b/challenge-075/mohammad-anwar/perl/ch-2.t @@ -3,7 +3,7 @@ # # Perl Weekly Challenge - 075 # -# Task #1: Coins Sum +# Task #2: Largest Rectangle Histogram # # https://perlweeklychallenge.org/blog/perl-weekly-challenge-075 # @@ -11,12 +11,10 @@ use strict; use warnings; use Test::More; +use List::Util qw(min max); -is coins_sum(prepare("1, 2"), 5), 3; -is coins_sum(prepare("1, 2, 3"), 5), 5; -is coins_sum(prepare("1, 2, 4"), 6), 6; -is coins_sum(prepare("25, 10, 5"), 30), 5; -is coins_sum(prepare("9, 6, 5, 1"), 11), 6; +is(largest_rectangle_histogram(prepare("2, 1, 4, 5, 3, 7")), 12, "example 1"); +is(largest_rectangle_histogram(prepare("3, 2, 3, 5, 7, 5")), 15, "example 2"); done_testing; @@ -24,44 +22,88 @@ done_testing; # # METHODS -sub coins_sum { - my ($coins, $sum) = @_; +sub largest_rectangle_histogram { + my ($list) = @_; - my $size = $#$coins; - return 0 if ($size == -1 || $sum <= 0); + my $i = 0; + my $max = 0; + foreach my $n (@$list) { - my $matrix; + my ($left, $right) = (0, 0); + $left = go_left($i, $list) if ($i > 0); + $right = go_right($i, $list) if ($i <= $#$list); - # Sum of 0 can be achieved in one possible way. - $matrix->[$_][0] = 1 for (0 .. $size+1); + my @heights = (@$list)[$i - $left .. $i + $right]; + my $size = min(@heights) * @heights; + $max = $size if ($size > $max); - foreach my $i (0 .. $size) { + $i++; + } - foreach my $j (1 .. $sum) { + return $max; +} - my $include_current = 0; - my $exclude_current = 0; +sub go_left { + my ($i, $list) = @_; - if ($coins->[$i] <= $j) { - $include_current = $matrix->[$i][$j - $coins->[$i]]; - } + my $c = $list->[$i]; + my $j = 0; + while ($i > 0) { + $i--; + last if ($list->[$i] < $c); + $j++; + } - if ($i > 0) { - $exclude_current = $matrix->[$i - 1][$j]; - } + return $j; +} + +sub go_right { + my ($i, $list) = @_; - $matrix->[$i][$j] = $include |
