1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
|
#!/usr/bin/env perl
# vim:set ts=4 sw=4 sts=4 et ai wm=0 nu:
#=============================================================================
# ch-1.pl
#=============================================================================
# Copyright (c) 2020, Bob Lied
#=============================================================================
# Perl Weekly Challenge 71 TASK #1 > Peak Element
#=============================================================================
#
# You are given positive integer $N (>1).
#
# Write a script to create an array of size $N with random unique elements
# between 1 and 50.
#
# In the end it should print peak elements in the array, if found.
# An array element is called peak if it is bigger than its neighbour.
#
# Example 1
# Array: [ 18, 45, 38, 25, 10, 7, 21, 6, 28, 48 ]
# Peak: [ 48, 45, 21 ]
#
# Example 2
# Array: [ 47, 11, 32, 8, 1, 9, 39, 14, 36, 23 ]
# Peak: [ 47, 32, 39, 36 ]
use strict;
use warnings;
use feature qw(say);
use Getopt::Long;
my ($MinVal, $MaxVal) = (1, 50);
sub Usage { "Usage: $0 N\n\tN>1" }
sub isPeak
{
my ($prev, $me, $next) = @_;
return ($prev < $me) && ($me > $next);
}
sub peakElement
{
my @arr = ($MinVal-1, @_, $MinVal-1);
my @peak = ();
my $last = $#arr - 1;
foreach ( 1..$last )
{
if ( isPeak($arr[$_-1], $arr[$_], $arr[$_+1] ) )
{
push @peak, $arr[$_]
}
}
return \@peak;
}
sub makeArray
{
my ($min, $max, $size) = @_;
my @chooseFrom = ( $min .. $max );
my @result;
for my $n ( 1..$size )
{
push @result, splice(@chooseFrom, int(rand(@chooseFrom)), 1)
}
return @result;
}
sub checkUniq
{
my (@arr) = @_;
my %uniq;
$uniq{$_}++ foreach @arr;
my $notUnique = grep { $_ != 1 } values %uniq;
return $notUnique == 0;
}
sub runTests
{
use Test::More;
is( scalar(makeArray(1, 50, 10)), 10, "Make random array size 10");
ok( checkUniq(makeArray(1, 50, 10)), "Random array unique elements");
is_deeply(peakElement(2, 1 ), [2], "two elements, left");
is_deeply(peakElement(1, 2 ), [2], "two elements, right");
is_deeply(peakElement(6, 4, 2 ), [6], "three elements, first");
is_deeply(peakElement(6, 8, 2 ), [8], "three elements, middle");
is_deeply(peakElement(6, 7, 9 ), [9], "three elements, last");
is_deeply(peakElement(8, 5, 9 ), [8,9], "three elements, both ends");
is_deeply(peakElement(1, 3, 5, 4), [5], "even # elements, middle peak ");
is_deeply(peakElement(9, 3, 5, 8), [9, 8], "even # elements, both ends ");
is_deeply(peakElement(9, 3, 4, 5, 8), [9, 8], "odd # elements, both ends ");
is_deeply(peakElement(3, 9, 4, 8, 5), [9, 8], "odd # elements, middle peaks");
is_deeply(peakElement(18, 45, 38, 25, 10, 7, 21, 6, 28, 48), [45, 21, 48], "example 1");
is_deeply(peakElement(47, 11, 32, 8, 1, 9, 39, 14, 36, 23), [47, 32, 39, 36], "example 2");
my ($result) = (done_testing())[0];
return $result;
}
########## MAIN ##########
my $doTest;
GetOptions('test!' => \$doTest);
exit(!runTests()) if $doTest;
my $N = $ARGV[0] // 0;
die Usage() unless $N > 1;
my @uniqArray = makeArray($MinVal, $MaxVal, $N);
my $peaks = peakElement @uniqArray;
say "Array: ", join ",", @uniqArray;
say "Peaks: ", join ",", @$peaks;
|