I’ve been doing the Weekly
Challenges. The
latest
involved filtering pairs and triplets out of a list. (Note that this
ends today.)

Task 1: Good Pairs

You are given a list of integers, `@list`

.

Write a script to find the total count of Good Pairs.

A pair `(i, j)`

is called good if `list[i] == list[j]`

and `i < j`

.

The simple, probably naïve, way of doing that is to look at each pair
of numbers, either by running the indices oneself or by using a
combination generator that does the same thing, and count the ones
that match. Here's a Perl version of that, using
`Algorithm::Combinatorics`

for the pairing:

```
sub goodpairs($l) {
my $c = 0;
my $i = combinations($l, 2);
while (my $x = $i->next) {
if ($x->[0] == $x->[1]) {
$c++;
}
}
return $c;
}
```

But this must inevitably be *O(n²)*, and I was sure it could be done
more efficiently – for example, by binning the input list into a hash,
then for each hash value adding the corresponding triangular number `n × (n-1) ÷ 2`

to the total (2 adds 1, 3 adds 3, 4 adds 6, 5 adds 10,
etc.) So here's that version, the one I actually wrote and submitted,
which on a 5,000-element list of random numbers `1..100`

runs four
orders of magnitude faster, and it's not even significantly longer.
(As an extra optimisation I divide by 2 just once at the end. It might
be worth looking into cacheing the triangular number values too.)

```
sub goodpairs($l) {
my $c = 0;
my %k;
map {$k{$_}++} @{$l};
foreach my $v (values %k) {
$c += $v * ($v-1);
}
return $c / 2;
}
```

Task 2: Good Triplets

You are given an array of integers, `@array`

and three integers
`$x,$y,$z`

.

Write a script to find out total Good Triplets in the given array.

A triplet array[i], array[j], array[k] is good if it satisfies the
following conditions:

```
a) 0 <= i < j < k <= n (size of given array)
b) abs(array[i] - array[j]) <= x
c) abs(array[j] - array[k]) <= y
d) abs(array[i] - array[k]) <= z
```

No room for optimisations here with those separate constraints, so
it's a matter of iterating over `(i, j, k)`

triplets. I can get one
short-cut out of this, by skipping the innermost `k`

loop if the `(i, j)`

pair will already fail the test. Kotlin:

```
fun goodtriplets(a: List<Int>, x: Int, y: Int, z: Int): Int {
var c = 0
for (i in 0..a.size-3) {
for (j in i+1..a.size-2) {
if (abs(a[i] - a[j]) <= x) {
for (k in j+1..a.size-1) {
if (abs(a[j] - a[k]) <= y &&
abs(a[i] - a[k]) <= z) {
c += 1
}
}
}
}
}
return c
}
```

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.