aboutsummaryrefslogtreecommitdiff
path: root/challenge-087/jo-37/perl/ch-1.pl
blob: acf4ed0550e649d031e0d97f92c473ddafbba486 (plain)
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
#!/usr/bin/perl

use Test2::V0;
use List::Util qw(reduce uniqnum);

# Find longest consecutive sequence in a list of integers.  An empty
# result in boolean context gives zero as requested.
sub lcs {
	# Sort unique values.
	my @sorted = uniqnum sort {$a <=> $b} @_;

	# Abusing "reduce" as a sliding window implementation for two
	# elements at a time.
	# Transform the sorted list into sawtooth shape, where every number
	# is shifted to zero if is not the successor of the previous.
	my @sawtooth;
	my $level;
	reduce {
			$level = $b if $b != $a + 1;
			push @sawtooth, $b - $level;
			$b
		} '-inf', @sorted;
	
	# Find the maximum and simultanously its position in the list.
	my $maxat = reduce {
			$sawtooth[$b] > $a->[0] ? [$sawtooth[$b], $b] : $a
		} ['-inf'], 0 .. $#sawtooth;

	# The longest consecutive list ends at the position of the maximum
	# and has one more element than the maximum in the sawtooth list.
	# Extract this sublist from the ordered list.  Empty the result list
	# if the maximum is zero, i.e.  if the lcs consists of a single
	# number.
	(@sorted[$maxat->[1] - $maxat->[0] .. $maxat->[1]]) x !!$maxat->[0];
}

is [lcs 100, 4, 50, 3, 2], [2, 3, 4], 'Example 1';
is lcs(20, 30, 10, 40, 50), F(), 'Example 2';
is [lcs 20, 19, 9, 11, 10], [9, 10, 11], 'Example 3';

is [lcs 1, 2, 3, 11, 12, 13, 14, 21, 22], [11, 12, 13, 14], 'max != index';
is [lcs 12, 3, 1, 14, 5, 2, 11, 3, 4, 13], [1, 2, 3, 4, 5], 'has duplicate';
is [lcs 1, 2.1, 3.2, 4.3, 5.3, 6.3, 7.2, 8.1, 9], [4.3, 5.3, 6.3],
	'works with broken numbers, too';

done_testing;