aboutsummaryrefslogtreecommitdiff
path: root/challenge-087/abigail
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
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')
-rw-r--r--challenge-087/abigail/node/ch-2.js56
-rw-r--r--challenge-087/abigail/perl/ch-2.pl57
2 files changed, 103 insertions, 10 deletions
diff --git a/challenge-087/abigail/node/ch-2.js b/challenge-087/abigail/node/ch-2.js
index 24c6c98040..5dedf7c4ce 100644
--- a/challenge-087/abigail/node/ch-2.js
+++ b/challenge-087/abigail/node/ch-2.js
@@ -12,12 +12,42 @@
//
//
-// 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
@@ -52,6 +82,19 @@ for (let x = 1; x < matrix . length; x ++) {
}
}
+let X = matrix . length;
+let Y = matrix [0] . length;
+
+//
+// Transpose if the matrix is wider than it is high.
+//
+let transposed = 0;
+if (X < Y) {
+ matrix = matrix [0] . map ((col, i) => matrix . map (row => row [i]));
+ [X, Y] = [Y, X];
+ transposed = 1;
+}
+
//
// Maps the 1s in the matrix to the number of consecutive 1s below
// it (including this 1 itself).
@@ -100,6 +143,9 @@ for (let x = 0; x < matrix . length; x ++) {
//
let output = "0";
if (best [0] * best [1] > 1) {
+ if (transposed) {
+ best = [best [1], best [0]];
+ }
let row = [... Array (best [1]) . keys ()] . map (_ => 1) . join (" ");
output = [... Array (best [0]) . keys ()] . map (_ => row) . join ("\n");
}
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];
}