The Weekly Challenge 307

Check Order and Find Anagrams

Task 1: Check Order

You are given an array of integers, @ints.

Write a script to re-arrange the given array in increasing order and return the indices where it differs from the original array.

Example 1

Input: @ints = (5, 2, 4, 3, 1) Output: (0, 2, 3, 4) Before: (5, 2, 4, 3, 1) After : (1, 2, 3, 4, 5)

Example 2

Input: @ints = (1, 2, 1, 1, 3) Output: (1, 3) Before: (1, 2, 1, 1, 3) After : (1, 1, 1, 2, 3)

Example 3

Input: @ints = (3, 1, 3, 2, 3) Output: (0, 1, 3) Before: (3, 1, 3, 2, 3) After : (1, 2, 3, 3, 3)

Logic

Sort the array, then compare element-by-element with the original. Collect indices where the values differ. Simple O(n log n) approach.

Perl Solution

ch-1.pl

#!/usr/bin/perl use strict; use warnings; use Test::More tests => 4; sub check_order { my ($ints_ref) = @_; my @original = @$ints_ref; my @sorted = sort { $a <=> $b } @original; my @diff_indices; for my $i (0 .. $#original) { push @diff_indices, $i if $original[$i] != $sorted[$i]; } return \@diff_indices; } is_deeply(check_order([5,2,4,3,1]), [0,2,3,4], 'Ex1'); is_deeply(check_order([1,2,1,1,3]), [1,3], 'Ex2'); is_deeply(check_order([3,1,3,2,3]), [0,1,3], 'Ex3'); is_deeply(check_order([1,2,3,4,5]), [], 'Sorted');

Python Solution

ch-1.py

def check_order(ints: list[int]) -> list[int]: sorted_ints = sorted(ints) return [i for i, (a, b) in enumerate(zip(ints, sorted_ints)) if a != b]

Task 2: Find Anagrams

You are given a list of words, @words.

Write a script to find any two consecutive words and if they are anagrams, drop the first word and keep the second. Continue until no more consecutive anagrams exist. Return the count of the final list.

Example 1

Input: @words = ("acca", "dog", "god", "perl", "repl") Output: 3 Step 1: "dog" and "god" are anagrams, drop "dog" => ("acca", "god", "perl", "repl") Step 2: "perl" and "repl" are anagrams, drop "perl" => ("acca", "god", "repl")

Example 2

Input: @words = ("abba", "baba", "aabb", "ab", "ab") Output: 2 Step 1: "abba" and "baba" are anagrams, drop "abba" => ("baba", "aabb", "ab", "ab") Step 2: "baba" and "aabb" are anagrams, drop "baba" => ("aabb", "ab", "ab") Step 3: "ab" and "ab" are anagrams, drop first "ab" => ("aabb", "ab")

Logic

Iteratively scan the list for consecutive anagram pairs. When found, remove the first word and restart from the beginning. Two words are anagrams if their sorted character sequences are identical. The process continues until a full pass finds no consecutive anagrams.

Perl Solution

ch-2.pl

#!/usr/bin/perl use strict; use warnings; use Test::More tests => 4; sub sorted_word { my ($word) = @_; return join '', sort split //, $word; } sub find_anagrams { my ($words_ref) = @_; my @list = @$words_ref; my $changed = 1; while ($changed) { $changed = 0; for my $i (0 .. $#list - 1) { if (sorted_word($list[$i]) eq sorted_word($list[$i+1])) { splice(@list, $i, 1); $changed = 1; last; } } } return scalar @list; } is(find_anagrams(["acca","dog","god","perl","repl"]), 3, 'Ex1'); is(find_anagrams(["abba","baba","aabb","ab","ab"]), 2, 'Ex2'); is(find_anagrams(["abc","cab","bca"]), 1, 'Chain'); is(find_anagrams(["word","drow","word","word"]), 1, 'Repeating');

Python Solution

ch-2.py

def sorted_word(word: str) -> str: return ''.join(sorted(word)) def find_anagrams(words: list[str]) -> int: lst = words[:] changed = True while changed: changed = False for i in range(len(lst) - 1): if sorted_word(lst[i]) == sorted_word(lst[i + 1]): lst.pop(i) changed = True break return len(lst)