The Bear's Den

Enter at your own risk

Meeting Strings

I refuse using the other title for this post.

Task 1: Power String

Submitted by: Mohammad Sajid Anwar


You are given a string.

Write a script to return the power of the given string.

The power of the string is the maximum length of a non-empty substring that contains only one unique character.

Example 1

Input: $str = "textbook"
Output: 2

Breakdown: "t", "e", "x", "b", "oo", "k"
The longest substring with one unique character is "oo".

Example 2

Input: $str = "aaaaa"
Output: 5

Example 3

Input: $str = "hoorayyy"
Output: 3

Breakdown: "h", "oo", "r", "a", "yyy"
The longest substring with one unique character is "yyy".

Example 4

Input: $str = "x"
Output: 1

Example 5

Input: $str = "aabcccddeeffffghijjk"
Output: 4

Breakdown: "aa", "b", "ccc", "dd", "ee", "ffff", "g", "h", "i", "jj", "k"
The longest substring with one unique character is "ffff".

Solution

Perl

Using PDL the solution is simple: Convert the characters to their integer representation, run-length-encode this array and find the maximum length.

use strict;
use warnings;
use PDL;
use PDL::Char;

sub power_string {
    (PDL::Char->new(shift)->long->rle)[0]->max;
}

See the full solution to task 1.

J

With my limited knowledge of this language, a solution was not so easy to find.

PowerString =: {{1 + >./ ([*+) /\. 2=/\ y}}
NB.              -E- -D- --B-- -C- -A--
  1. pairwise compare list elements
  2. define a special "increment or zero" operation between a binary left operand x and an integer right operand y that acts as x ([*+) y = x * (x + y). If the left operand is zero, it returns zero. Otherwise it increments the right operand.
  3. apply the increment or zero operation to successive list suffixes, counting successive ones
  4. find the maximum over the list
  5. add 1 to get the requested power

There is an edge case that needs to be treated separatly:
The power of a string having a length less than two is its length.

See the full solution.

Task 2: Meeting Point

Submitted by: Mohammad Sajid Anwar


You are given instruction string made up of U (up), D (down), L (left) and R (right).

Write a script to return true if following the instruction, you meet (0,0) at any point along the sequence.

Example 1

Input: $path = "ULD"
Output: false

(-1,1) <- (0,1)
   |        ^
   v        |
(-1,0)    (0,0)

Example 2

Input: $path = "ULDR"
Output: true

 (-1,1) <- (0,1)
    |        ^
    v        |
 (-1,0) -> (0,0)

Example 3

Input: $path = "UUURRRDDD"
Output: false

(0,3) -> (1,3) -> (2,3) -> (3,3)
  ^                          |
  |                          v
(0,2)                      (3,2)
  ^                          |
  |                          v
(0,1)                      (3,1)
  ^                          |
  |                          v
(0,0)                      (3,0)

Example 4

Input: $path = "UURRRDDLLL"
Output: true

(0,2) -> (1,2) -> (2,2) -> (3,2)
  ^                          |
  |                          v
(0,1)                      (3,1)
  ^                          |
  |                          v
(0,0) <- (1,0) <- (1,1) <- (3,0)

Example 5

Input: $path = "RRUULLDDRRUU"
Output: true

(0,2) <- (1,2) <- (2,2)
  |                 ^
  v                 |
(0,1)             (2,1)
  |                 ^
  v                 |
(0,0) -> (1,0) -> (2,1)


Solution

A general approach is:

J

Starting with the solution:

Dir =: 'UDRL'
Move =: 5 2 $ 1 0 _1 0 0 1 0 _1 0 0
MeetingPoint =: {{(0 0) e. +/\ (Dir i. y) { Move}}
NB.               ---D---- -C- ----A----- --B---

with this explanation:

  1. Find the indices of the instruction letters
  2. Pick the corresponding moves
  3. Calculate the cumulative sums
  4. Search for the zero point

Any letter different from UDRL will produce the index 4 that is mapped to the null vector in Move and is thus ignored.

See the full solution to task 2.

Perl

My first solution in Perl used the moves 1, -1, i and -i in the complex plane, permitting scalar addition for each move.

But after I had written the implementation in J, I wanted a loopless and comparable solution in Perl and therefore switched to PDL.

The steps are almost identical.

use strict;
use warnings;
use PDL;
use PDL::NiceSlice;

sub meeting_point {
    state $dir = {U => 0, D => 1, R => 2, L => 3};
    state $move = long('1, 0; -1, 0; 0, 1; 0, -1')->xchg(0, 1);
    state $point = long 0, 0;
    my $instr = indx grep defined, $dir->@{split //, shift};

    any eqvec $point, $move($instr)->cumusumover->xchg(0,1);
}

See the full solution to task 2.