I’ve been doing the Weekly
Challenges. The
latest
involved sorting words and modifying sequences. (Note that this is
open until 7 May 2023.)
Task 1: Odd one Out
You are given a list of words (alphabetic characters only) of same
size.
Write a script to remove all words not sorted alphabetically and
print the number of words in the list that are not alphabetically
sorted.
The simplest-to-program way to find out whether a string is sorted is
to sort its contents, then compare with the original. Perl:
sub oddoneout($a) {
my $ct = 0;
foreach my $s (@{$a}) {
my $t = join('', sort split '',$s);
if ($s ne $t) {
$ct++;
}
}
return $ct;
}
A computationally cheaper approach, which I used in some languages
where it felt more idiomatic, is to look at the characters pairwise,
and bail out if character N-1
is greater in value than character
N
. PostScript:
/oddoneout {
3 dict begin
/ct 0 def
{
/s exch def
1 1 s length 1 sub {
/i exch def
s i 1 sub get s i get gt {
/ct ct 1 add def
exit
} if
} for
} forall
ct
end
} bind def
Task 2: Number Placement
You are given a list of numbers having just 0 and 1. You are also given placement count (>=1).
Write a script to find out if it is possible to replace 0 with 1 in
the given list. The only condition is that you can only replace when
there is no 1 on either side. Print 1 if it is possible otherwise 0.
One could try actually inserting the values, but I noticed that for
each run of zeroes of length n
I can perform (n - 1) / 2
(rounded
down) replacements. Length 3 gives 1, as does length 4; length 5 gives
2, as does length 6; and so on.
So all I do is count the lengths of the zero runs, then work out from
that the total number of possible replacements. If that's no lower
than the number I'm asked for, return true
.
I'm iterating over overlapping pairs of numbers, and using windowed
or rotor
in the languages that support it would make some sense –
but I also need the index value, so it seemed easier to avoid the
extra complication rather than mucking about with enumerate
etc.
Rust:
fn numberplacement(a0: Vec<u8>, ct: u32) -> bool {
Set up a list that wraps the original with "1" entries, so that all
runs of zero are bounded - this saves special-case code for the start
and end of the array later.
let mut a: Vec<u8> = vec![1; a0.len() + 2];
a.splice( 1 ..= a0.len(), a0);
let mut s = 0;
let mut tt = 0;
Starting at the second entry and running to the end:
for i in 1 .. a.len() {
Look for patterns of previous and current entry.
match (a[i - 1], a[i]) {
If it's the start of a run, note the index.
(1, 0) => { s = i; },
If it's the end of a run, add the number of possible substitutions.
(0, 1) => { tt += (i - s) / 2; },
Otherwise, ignore.
_ => (),
}
}
ct <= tt as u32
}
…all right, I like match
and I think it's clear, but it's easily
enough phrased more conventionally, as in Raku:
sub numberplacement(@a0, $ct) {
my @a = (1, );
@a.append(@a0);
@a.push(1);
my $s = 0;
my $tt = 0;
for (1..@a.end) -> $i {
if (@a[$i - 1] == 1 && @a[$i] == 0) {
$s = $i;
} elsif (@a[$i - 1] == 0 && @a[$i] == 1) {
$tt += floor(($i - $s)/2);
}
}
return $ct <= $tt;
}
Full code on
github.
Comments on this post are now closed. If you have particular grounds for adding a late comment, comment on a more recent post quoting the URL of this one.