Nothing too clever on this one, just a vector and some character comparison.
I used a Set for identifying duplicates. Is there an easy way to convert an array into a Set that doesnβt involve looping?
My implementation (299 SLoC) :: Ada centric solution
- Implementing a generic Round Robin buffer with a
Protected type
- Implementing generic of generic
- Using
Ada.Strings.Maps
for the fun (beauty) of it - Using
Ada.Text_IO.Text_Streams
to handle the input (data stream as in real life)
Have a look at my puzzle_06
In Ada 2022 you can use 'Reduce
attribute, like this:
pragma Ada_2022;
pragma Extensions_Allowed (On);
with Ada.Containers.Ordered_Sets;
procedure Main is
package Sets is new Ada.Containers.Ordered_Sets (Character, "<", "=");
Arr : String (1 .. 5) := "abcde";
S : Sets.Set := Arr'Reduce (Sets.Insert, Sets.Empty);
begin
-- Insert code here.
null;
end Main;
But this just hides looping.
You could use an occurrence counter. You do a β+1β for the new character and a β-1β for the character the goes out of the slice which is the marker candidate.
In my solution I use a simple array, so there is an explicit loop for testing duplicates, but probably there is a smarter structure for that. Or the same structure, but an additional variable that keeps the number of characters with duplicates. If the β+1β moves the number of occurrences of a given character to 2, it makes one more duplicate; if the β-1β decreases that number to 1, there is a duplicate less. When the duplicates counter is 0, you stop. NB: just thinking loud, untested idea.
It was definitely worth considering that idea
Loop for checking duplicates Duplicates counter Gain HAC 0.058 0.016 3.6x GNAT 0.00056 0.00027 2x
New version here.