I’ve been doing the Weekly
Challenges. The
latest
involved array analysis and matrix incrementing. (Note that this ends
today.)
Task 1: Smaller Than Current
You are given an array of numbers, @num1
.
Write a script to return an array, @num2
, where $num2[i]
is the
count of all numbers less than or equal to $num1[i]
.
My visualisation of this is: if the list is sorted into ascending
order, the number of items strictly less than any value is the index
of that value's first occurrence. Thus for example with first
occurrences in bold:
index |
0 |
1 |
2 |
3 |
value |
1 |
2 |
2 |
3 |
So step 1 is to create a sorted copy of the list; step 2 is to drop
the appropriate index values into a hash; and step 3 is to take the
original list, map each value to its hash entry, and return the
result. In Perl:
sub smallerthancurrent($a) {
Make the sorted copy of the list.
my @b = sort {$::a <=> $::b} @{$a};
my %m;
Step through the sorted list.
while (my ($i, $v) = each @b) {
If there's no hash entry for that value, create it.
unless (exists $m{$v}) {
$m{$v} = $i;
}
}
Read out the hash value for each member of the original list.
return [map {$m{$_}} @{$a}];
}
Task 2: Odd Matrix
You are given row
and col
, also a list of positions in the
matrix.
Write a script to perform action on each location (0-indexed) as
provided in the list and find out the total odd valued cells.
For each location (r, c), do both of the following:
a) Increment by 1 all the cells on row r.
b) Increment by 1 all the cells on column c.`
The obvious way of doing this is to spin up the actual matrix and
increment the values.
But, and I admit this was after I had written that code (in all twelve
languages) I had an idea. First of all let's ignore the actual values
and just say that in the end state a given cell is "flipped"
(incremented 1, 3, 5, ... times) or "un-flipped" (incremented 0, 2, 4,
... times).
Consider a matrix of known size with known numbers of flipped rows and
flipped columns. Each row contributes a flipped cell for each
un-flipped column, and each column contributes a flipped cell for each
un-flipped row. (The intersections would be double-counted, but since
by definition they aren't ever flipped that doesn't matter.)
So all I need to construct from the list of points is the liara of
flipped rows and columns in the final configuration.
This isn't a great deal shorter in lines of code than working through
the process in full, but it should run rather faster since there's no
nested loop of rows and columns; it removes the need to allocate and
scan the whole matrix, which would be significant if the code were to
be applied to more than trivial problems.
Scala:
def oddmatrix(rows: Int, cols: Int, points: List[List[Int]]): Int = {
Construct sets, to track which rows and which columns are flipped.
var rm = mutable.Set.empty[Int]
var cm = mutable.Set.empty[Int]
Iterate through the points.
for (p <- points) {
If this row is already flipped, remove it from the row set to count it
as un-flipped.
if (rm.contains(p(0))) {
rm -= p(0)
Otherwise, add it to the set to count it as flipped.
} else {
rm += p(0)
}
Do the same for the column flip.
if (cm.contains(p(1))) {
cm -= p(1)
} else {
cm += p(1)
}
}
Then simply read out (flipped rows × un-flipped columns) + (flipped
columns × un-flipped rows).
rm.size * (cols - cm.size) +
cm.size * (rows - rm.size)
}
Full code on
github.