BFE.dev solution for JavaScript Coding Question
9. decode message

This solution was created by @keego :)

The Problem

Given a 2D array of characters, we're tasked with finding the "hidden" message contained within it by creating a diagonal path that zig-zags through the array and returning the characters collected along that path.

In the provided example, we see the following message

I B C A L K A
D R F C A E A
G H O E L A D

decodes to

IROCLED

i.e

I       L    
  R   C   E  
    O       D

The Approach

One way to approach this is to have a starting point and a direction, and change the direction of travel based on certain boundary positions. We do this until an end condition is met.

Since we have a 2D array, we can assume this message grid is represented as rows of columns, i.e.

const message = [
  ['I', 'B', ...],
  ['D', 'R', ...],
  ['G', 'H', ...],
]

Starting at row 0 column 0, we'll want to descend to the right (incrementing the row and incrementing the column), then eventually ascend to the right (decrementing the row and incrementing the column). We end when there are no columns remaining. We can start with an empty string and, at each step, append the character found at the current position to the string.

We can represent this logically with the following pseudo code

// start at 0,0
// while there are still columns
//  1. append current character
//  2. if we've reached a row boundary
//      change direction
//  3. update position based on direction
// return accumulated string

The Catches

We'll want to keep in mind the following edge cases:

  • the naive empty input [[]]
  • the other potential empty input []
  • inputs with only 1 row
  • inputs with only 1 column

We should also be mindful of the ordering of the main parts of our loop and how they interact:

  • capturing the character
  • changing the direction
  • updating position

What should our starting position and direction be to allow our logic to remain simple?

The Solution

/**
 * @param {string[][]} message
 * @return {string}
 */
function decode(message) {
  // the direction in which we update our row position
  // we want to start in the "upward" direction, since
  // that will be the initial direction we'll have whenever
  // we reach the top row boundary later on
  let direction = -1
  // current row and column indexes, starting top left
  let row = 0
  let column = 0
  // our final string to be built up as we traverse
  let decoded = ''

  // we continue to loop until there are no more columns,
  // as soon as the size of the current row stops being
  // greater than the column index, we stop.
  // we also include an optional chaining operator
  // to stop us in case there are no more rows.
  while (message[row]?.length > column) {
    // 1. append current character
    decoded += message[row][column]

    // 2. if we've reached a row boundary
    if (row === 0 || row === message.length - 1) {
      // change direction
      direction *= -1
    }

    // 3. update position based on direction
    row += direction
    column += 1
  }

  // return accumulated string
  return decoded
}

The Test

/**
 * @param {string[][]} message
 * @return {string}
 */
function decode(message) {
  let direction = -1
  let row = 0
  let column = 0
  let decoded = ''

  // log our input
  console.log({ message })

  while (message[row]?.length > column) {
    decoded += message[row][column]

    if (row === 0 || row === message.length - 1) {
      direction *= -1
    }

    row += direction
    column += 1
  }

  // log our output
  console.log({ decoded })

  return decoded
}

// given example input
const message1 = [
  'I B C A L K A',
  'D R F C A E A',
  'G H O E L A D',
].map(line => line.split(' '))

// run it and verify output
decode(message1)

We can also add additional test cases to verify our solution, as well as add additional logging for debugging.

Complexity

Given Nr rows of Nc columns...

This solution should be linear time complexity, scaling with the number of columns Nc.

  • That is the number of iterations we loop over, and all operations in the loop are O(1)

This solution should be linear space complexity, also scaling with the number of columns Nc.

  • All variables are O(1) except the accumulated string, which will have Nc characters.
  • This is non-recursive and calls no other functions so the stack size requirements will also be 1.
You might also be able to find a solution fromcommunity posts or fromAI solution.