aboutsummaryrefslogtreecommitdiff
path: root/challenge-054/andrezgz/perl/ch-1.pl
blob: 86d93d26707f11f7b9c771c9f2cf2fe8a70bed2e (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
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
#!/usr/bin/perl

# https://perlweeklychallenge.org/blog/perl-weekly-challenge-054/
# Task #1
#
# kth Permutation Sequence
# Write a script to accept two integers n (>=1) and k (>=1).
# It should print the kth permutation of n integers.
# For more information, please follow the wiki page.
# https://en.wikipedia.org/wiki/Permutation#k-permutations_of_n
#
# For example, n=3 and k=4, the possible permutation sequences are listed below:
#
# 123
# 132
# 213
# 231
# 312
# 321
#
# The script should print the 4th permutation sequence 231.

use strict;
use warnings;

my $usage = "USAGE: $0 <n> <k>\n";

die $usage unless @ARGV == 2;

my ($n, $k) = @ARGV;

die $usage . '<n> should be greater or equal to 1'
    if ($n !~/^\d+$/ || $n < 1);
die $usage . '<k> should be greater or equal to 1'
    if ($k !~/^\d+$/ || $k < 1);

my $n_max_perm = factorial($n);
die $usage . "$n integers have $n_max_perm permutations,"
           . "so <k> should be less than $n_max_perm\n"
    if ($k > $n_max_perm);

my $perm_n = 0;
permute( [1..$n]);

sub permute {
    my $numbers = shift;
    my $perm = shift // '';

    if (!@$numbers){
        die $perm.$/ if (++$perm_n == $k); #finish on kth permutation
        return;
    }

    foreach my $i (0 .. @$numbers-1) {
        my $c = $numbers->[$i];
        my @new_n = grep { $_ != $c } @$numbers;
        permute( \@new_n  , $perm . $c);
    }
    return;
}

sub factorial {
    my $n = shift;
    return 1 if ($n == 0);
    return $n * factorial($n-1);
}

__END__

./ch-1.pl 5 60
32541

./ch-1.pl 5 120
54321

./ch-1.pl 5 121
USAGE: ./ch-1.pl <n> <k>
5 integers have 120 permutations,so <k> should be less than 120