Skip to content

Commit d06215e

Browse files
committed
297 Blogged
1 parent 84fc8ae commit d06215e

File tree

1 file changed

+307
-0
lines changed

1 file changed

+307
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,307 @@
1+
---
2+
layout: post
3+
title: "Semi-Ordered Life: Weekly Challenge #297"
4+
author: "Dave Jacoby"
5+
date: "2024-11-27 15:45:47 -0500"
6+
categories: ""
7+
---
8+
9+
Welcome to [**_Weekly Challenge #297!_**](https://theweeklychallenge.org/blog/perl-weekly-challenge-297/) **297** is the product of **3, 3, 3 and 11**, and is also the telephone country code for Aruba.
10+
11+
I'm continuing in implementing my solutions in both Perl and Python, so I expand my horizons with languages. Considering Javascript and Ruby as possible additions.
12+
13+
### Task 1: Contiguous Array
14+
15+
> Submitted by: Mohammad Sajid Anwar
16+
> You are given an array of binary numbers, `@binary`.
17+
>
18+
> Write a script to return the maximum length of a contiguous subarray with an equal number of `0` and `1`.
19+
20+
#### Let's Talk About it
21+
22+
This is another solution where you go over a subset of the array over and over again. I go `for my $i ( start .. finish ) { for my $j ( $i + 1 .. finish ) { ... } }` but could see the same with `for my $i ( start .. finish ) { for my $j ( start .. $i - 1 ) }`. I'm sure there's a one-pass take, which would be **O(n)** instead of **O(nlogn)** (I think), but I think this is readable for other developers, including yoruself at a less clever state.
23+
24+
Anyway, big loop picks one side of an array subset, small loop picks the other, we take that subset and count the ones and zeros. I think that `2 * ( sum0(@array)) == scalar(@array)` would probably be a good test, but I went with counting ones and zeros.
25+
26+
From there, we start with `$longest = -1` and `$longest = $length if $length > $longest`, because we're looking for the count, not the values or indexes.
27+
28+
In retrospect, pulling out functions for `just_zero` and `just_one` makes a lot more sense when the functions are not one-line things, and there's probably similar one-line solutions in Python I just don't know yet. Alas.
29+
30+
#### Show Me the Code!
31+
32+
```perl
33+
#!/usr/bin/env perl
34+
35+
use strict;
36+
use warnings;
37+
use experimental qw{ say state postderef signatures };
38+
39+
my @examples = (
40+
41+
[ 1, 0 ],
42+
[ 0, 1, 0 ],
43+
[ 0, 0, 0, 0, 0 ],
44+
[ 0, 1, 0, 0, 1, 0 ],
45+
);
46+
47+
for my $example (@examples) {
48+
my $input = join ', ', $example->@*;
49+
my $output = continuous_array($example);
50+
51+
say <<"END";
52+
Input: \@binary = ($input)
53+
Output: $output
54+
END
55+
}
56+
57+
sub continuous_array ($array) {
58+
my $l = 0;
59+
my $max = -1 + scalar $array->@*;
60+
for my $i ( 0 .. $max ) {
61+
for my $j ( $i + 1 .. $max ) {
62+
my @local = map { $array->[$_] } $i .. $j;
63+
my $len = 1 + ( $j - $i );
64+
my $z = just_zero(@local);
65+
my $o = just_one(@local);
66+
next unless $z == $o;
67+
if ( $len > $l ) { $l = $len; }
68+
}
69+
}
70+
return $l;
71+
}
72+
73+
sub just_zero (@array) {
74+
return scalar grep { $_ == 0 } @array;
75+
}
76+
77+
sub just_one (@array) {
78+
return scalar grep { $_ == 1 } @array;
79+
}
80+
```
81+
82+
```python
83+
#!/usr/bin/python3
84+
85+
86+
def main():
87+
examples = [
88+
[1, 0],
89+
[0, 1, 0],
90+
[0, 0, 0, 0, 0],
91+
[0, 1, 0, 0, 1, 0],
92+
]
93+
for e in examples:
94+
s = []
95+
for i in e:
96+
s.append(str(i))
97+
input = ", ".join(s)
98+
output = continuous_array(e)
99+
print(f" Input: binary = ({input})")
100+
print(f" Output: {output}")
101+
print("")
102+
103+
104+
def continuous_array(array):
105+
l = 0
106+
max = 1 + len(array)
107+
for i in range(0, max):
108+
for j in range(i + 1, max):
109+
indexes = [*range(i, j)]
110+
values = [array[k] for k in indexes]
111+
length = len(indexes)
112+
zeros = 0
113+
ones = 0
114+
for v in values:
115+
if v == 0:
116+
zeros += 1
117+
if v == 1:
118+
ones += 1
119+
if zeros == ones:
120+
if length > l:
121+
l = length
122+
return l
123+
124+
125+
if __name__ == "__main__":
126+
main()
127+
```
128+
129+
```text
130+
$ ./ch-1.pl && ./ch-1.py
131+
Input: @binary = (1, 0)
132+
Output: 2
133+
134+
Input: @binary = (0, 1, 0)
135+
Output: 2
136+
137+
Input: @binary = (0, 0, 0, 0, 0)
138+
Output: 0
139+
140+
Input: @binary = (0, 1, 0, 0, 1, 0)
141+
Output: 4
142+
143+
Input: binary = (1, 0)
144+
Output: 2
145+
146+
Input: binary = (0, 1, 0)
147+
Output: 2
148+
149+
Input: binary = (0, 0, 0, 0, 0)
150+
Output: 0
151+
152+
Input: binary = (0, 1, 0, 0, 1, 0)
153+
Output: 4
154+
155+
```
156+
157+
### Task 2: Semi-Ordered Permutation
158+
159+
> Submitted by: Mohammad Sajid Anwar
160+
> You are given permutation of `$n` integers, `@ints`.
161+
>
162+
> Write a script to find the minimum number of swaps needed to make the `@ints` a semi-ordered permutation.
163+
>
164+
> > A permutation is a sequence of integers from `1` to `n` of length `n` containing each number exactly once.
165+
> > A permutation is called semi-ordered if the first number is `1` and the last number equals `n`.
166+
>
167+
> You are ONLY allowed to pick adjacent elements and swap them.
168+
169+
#### Let's Talk About it
170+
171+
This _could_ look like a job for recursion, if you really wanted it to be, but it struck me that it's a simple `while` loop to move a character to the right position in an array.
172+
173+
There are only two requirements:
174+
175+
- the array must start with 1
176+
- the array must end with the highest values
177+
178+
So, we only need methods to move `1` one to the left and `max` one to the right. We also need to know the index where `$array[i] == $min` and `$array[i] == $max`.
179+
180+
How do you swap values? Like you want to make `$c = $d` and `$d = $c` without making both values equal what `$d` was at the start. I remember being taught `my $scratch = $c; $c = $d; $d = $scratch`, but when you have anonymous arrays? `( $c, $d ) = ( $d, $c )` and you don't need to create more variables.
181+
182+
A quick search into Python didn't give me an equivalent to `first` from [List::Util](https://metacpan.org/pod/List::Util). I have no idea if my search skills were insufficient or not, so I wrote `first_index_that_equals`, which is a wonder in both code and naming.
183+
184+
(List::Util is such a handy multitool of a module, I'm beginning to think I should write up discrete implementations of functions for Challenge problems, rather than keep going back to the well.)
185+
186+
So, there's iteration, while loops, swapping two values, finding the first index that matches. Is there anything else that needs explaining?
187+
188+
Oh, one Python thing that I might be the last developer in America to understand: There's a list we call `mylist`. We can get the size of the list with `len(mylist)`. We can create a list going from `0` to `n-1` with `range(n)`. Except when we want to use it, we get `"range(0,5)"` instead of the list of indexes, `[0, 1, 2, 3, 4]`. So I think that I need to assert that I want a list with `[range(0,n)]`, but then I get `"[range(0,5)]"`. I have to dereference it with `[*range(0,n)]`.
189+
190+
#### Show Me the Code!
191+
192+
```perl
193+
#!/usr/bin/env perl
194+
195+
use strict;
196+
use warnings;
197+
use experimental qw{ say state postderef signatures };
198+
199+
use List::Util qw{first};
200+
201+
my @examples = (
202+
203+
[ 2, 1, 4, 3 ],
204+
[ 2, 4, 1, 3 ],
205+
[ 1, 2, 3, 4, 5 ],
206+
[ 9, 8, 7, 6, 2, 3, 4, 5, 1 ],
207+
);
208+
209+
for my $example (@examples) {
210+
my $output = semi_ordered_permute( $example->@* );
211+
my $input = join ', ', $example->@*;
212+
say <<"END";
213+
Input: \@ints = ($input)
214+
Output: $output
215+
END
216+
}
217+
218+
sub semi_ordered_permute (@array) {
219+
my $min = 1;
220+
my $max = scalar @array;
221+
my $steps = 0;
222+
while ( $array[0] != $min ) {
223+
my $i = first { $min == $array[$_] } 0 .. -1 + $max;
224+
( $array[$i], $array[ $i - 1 ] ) = ( $array[ $i - 1 ], $array[$i] );
225+
$steps++;
226+
}
227+
while ( $array[-1] != $max ) {
228+
my $i = first { $max == $array[$_] } 0 .. -1 + $max;
229+
( $array[$i], $array[ $i + 1 ] ) = ( $array[ $i + 1 ], $array[$i] );
230+
$steps++;
231+
}
232+
return $steps;
233+
}
234+
```
235+
236+
```python
237+
#!/usr/bin/python3
238+
239+
def main():
240+
examples = [
241+
[2, 1, 4, 3],
242+
[2, 4, 1, 3],
243+
[1, 2, 3, 4, 5],
244+
[9, 8, 7, 6, 2, 3, 4, 5, 1],
245+
]
246+
for e in examples:
247+
input = ", ".join(str(i) for i in e)
248+
output = semi_ordered_permute(e)
249+
print(f" Input: ints = [{input}]")
250+
print(f" Output: {output}")
251+
print("")
252+
253+
254+
def semi_ordered_permute(array):
255+
max = len(array)
256+
min = 1
257+
steps = 0
258+
while min != array[0]:
259+
i = first_index_that_equals(array, min)
260+
(array[i], array[i - 1]) = (array[i - 1], array[i])
261+
steps += 1
262+
while max != array[-1]:
263+
i = first_index_that_equals(array, max)
264+
(array[i], array[i + 1]) = (array[i + 1], array[i])
265+
steps += 1
266+
return steps
267+
268+
269+
def first_index_that_equals(array, value):
270+
indexes = [*range(len(array))]
271+
for i in [*range(len(array))]:
272+
if value == array[i]:
273+
return i
274+
275+
276+
if __name__ == "__main__":
277+
main()
278+
```
279+
280+
```text
281+
$ ./ch-2.pl && ./ch-2.py
282+
Input: @ints = (2, 1, 4, 3)
283+
Output: 2
284+
285+
Input: @ints = (2, 4, 1, 3)
286+
Output: 3
287+
288+
Input: @ints = (1, 2, 3, 4, 5)
289+
Output: 0
290+
291+
Input: @ints = (9, 8, 7, 6, 2, 3, 4, 5, 1)
292+
Output: 15
293+
294+
Input: ints = [2, 1, 4, 3]
295+
Output: 2
296+
297+
Input: ints = [2, 4, 1, 3]
298+
Output: 3
299+
300+
Input: ints = [1, 2, 3, 4, 5]
301+
Output: 0
302+
303+
Input: ints = [9, 8, 7, 6, 2, 3, 4, 5, 1]
304+
Output: 15
305+
```
306+
307+
#### If you have any questions or comments, I would be glad to hear it. Ask me on [Mastodon](https://mastodon.xyz/@jacobydave) or [make an issue on my blog repo.](https://github.com/jacoby/jacoby.github.io)

0 commit comments

Comments
 (0)