aboutsummaryrefslogtreecommitdiff
path: root/challenge-087/abigail/perl
diff options
context:
space:
mode:
authorAbigail <abigail@abigail.be>2020-11-19 15:54:48 +0100
committerAbigail <abigail@abigail.be>2020-11-19 15:54:48 +0100
commitce3af91346700d98b3a0ef1c482b1388b63c4e6f (patch)
treef51c0806bb54ea739307c0a26fa970fd898a5f8a /challenge-087/abigail/perl
parent8e06dc7df8c704eb79f454881c2a954e2c0b8eb6 (diff)
downloadperlweeklychallenge-club-ce3af91346700d98b3a0ef1c482b1388b63c4e6f.tar.gz
perlweeklychallenge-club-ce3af91346700d98b3a0ef1c482b1388b63c4e6f.tar.bz2
perlweeklychallenge-club-ce3af91346700d98b3a0ef1c482b1388b63c4e6f.zip
Transpose the matrix if it's wider than it's high.
Diffstat (limited to 'challenge-087/abigail/perl')
-rw-r--r--challenge-087/abigail/perl/ch-2.pl57
1 files changed, 52 insertions, 5 deletions
diff --git a/challenge-087/abigail/perl/ch-2.pl b/challenge-087/abigail/perl/ch-2.pl
index b2bf30348d..8cdb86227e 100644
--- a/challenge-087/abigail/perl/ch-2.pl
+++ b/challenge-087/abigail/perl/ch-2.pl
@@ -47,12 +47,42 @@ use experimental 'lexical_subs';
#
#
-# A naive implementation would be a quartic algorithm. We can do better,
-# using a cubic algorithm.
+# A naive implementation would be a for each pair of points see whether
+# there's a rectangle with 1s, with the pair of points opposite vertices
+# of the array.
#
-# First, we replace every 1 in the matrix with the number of from the
-# current position to the first 0 below it. We can do this in a single
-# pass, working bottom to top.
+# If done correctly, that leads to an Omega (l^2 * m^2) algorithm,
+# if the size of the input is an l x m matrix. So, Omega (N^2)
+# where N = l * m.
+#
+# But we can do better. We can use an algorithm which runs in
+# O (l * m * min (l, m)) time, or O (N sqrt (N)) time, since
+# min (l, m) <= sqrt (N).
+#
+# Assume the matrix is not wider than it is high (otherwise, first
+# transpose the matrix -- which can be done in O (l * m) time).
+#
+# First, we replace every 1 in the matrix with how many 1's (including
+# the 1 in the current position) it takes the hit the first 0 below it.
+# We can do this in a single pass, working bottom to top.
+#
+# So, the matrix
+#
+# 0 1 0 1 1
+# 0 1 0 1 1
+# 0 1 1 1 1
+# 1 0 0 1 1
+# 0 0 0 1 1
+# 0 0 1 0 0
+#
+# becomes
+#
+# 0 3 0 5 5
+# 0 2 0 4 4
+# 0 1 1 3 3
+# 1 0 0 2 2
+# 0 0 0 1 1
+# 0 0 1 0 0
#
# Then, for each cell (x, y) in the matrix, we scan to the right (in the
# y direction), until we hit a zero (or the end of the row). For each
@@ -77,6 +107,22 @@ my $X = @matrix;
my $Y = @{$matrix [0]};
#
+# Transpose if necessary
+#
+my $transpose;
+if ($X < $Y) {
+ my @matrix_t;
+ for (my $x = 0; $x < $X; $x ++) {
+ for (my $y = 0; $y < $Y; $y ++) {
+ $matrix_t [$y] [$x] = $matrix [$x] [$y];
+ }
+ }
+ @matrix = @matrix_t;
+ ($X, $Y) = ($Y, $X);
+ $transpose = 1;
+}
+
+#
# Fill the matrix with runs.
#
for (my $x = $X - 2; $x >= 0; $x --) {
@@ -113,6 +159,7 @@ if ($$best [0] * $$best [1] <= 1) {
say 0;
}
else {
+ $best = [$$best [1], $$best [0]] if $transpose;
say join " ", (1) x $$best [1] for 1 .. $$best [0];
}