品番

#010

13th Dec 2023 /

Solutions for AdventJS 2023 by @Midudev

Intro:

From December 1st to 24th, for the third consecutive year, we are participating in @midudev’s AdventJS. On this occasion I would like to leave you a small review of how I’m solving the exercises. Easy and practical for novices like me ❤️.

1: First Repeated Gift!

Task:

In the North Pole toy factory, each toy has a unique identification number.

However, due to an error in the toy machine, some numbers have been assigned to more than one toy.

Find the first identification number that has been repeated, where the second occurrence has the smallest index!

In other words, if there is more than one repeated number, you must return the number whose second occurrence appears first in the list. If there are no repeated numbers, return -1.

const giftIds = [2, 1, 3, 5, 3, 2];
const firstRepeatedId = findFirstRepeated(giftIds);
console.log(firstRepeatedId); // 3
// Although both 2 and 3 are repeated
// 3 appears second first

const giftIds2 = [1, 2, 3, 4];
const firstRepeatedId2 = findFirstRepeated(giftIds2);
console.log(firstRepeatedId2); // -1
// It's -1 since no number is repeated

const giftIds3 = [5, 1, 5, 1];
const firstRepeatedId3 = findFirstRepeated(giftIds3);
console.log(firstRepeatedId3); // 5

Note! The elves say this is a Google technical interview question.

Solution:

// 360 pts
function findFirstRepeated(gifts) {
  return gifts.find((gift, index) => gifts.indexOf(gift) !== index) ?? -1;
}

Now, why did I do it this way and what alternatives are there?

Efficiency: Using find and indexOf is easy to understand, but if you have a very long list, it can be somewhat slow because it has to traverse it multiple times. If you’re concerned about efficiency, you could think of faster ways, but sometimes simplicity is key.

Alternative with Set: You could use a Set, which automatically removes duplicates, and then compare the original length with the Set’s length. But be careful, the order of the gifts may change.

Defining something like this inside the function:

const set = new Set(gifts);

In the end, there are several ways to tackle this problem, but it ultimately depends on how big the “party” is and how much efficiency matters to you. I hope the function is clearer now!

2: Starting up the Factory

Task:

In Santa’s workshop, the elves have a gift list they want to make and a limited set of materials.

The gifts are strings and the materials are characters. Your task is to write a function that, given a list of gifts and the available materials, returns a list of gifts that can be made.

A gift can be made if we have all the necessary materials to make it.

const gifts = ["tren", "oso", "pelota"];
const materials = "tronesa";

manufacture(gifts, materials); // ["tren", "oso"]
// 'tren' YES because its letters are in 'tronesa'
// 'oso' YES because its letters are in 'tronesa'
// 'pelota' NO because its letters are NOT in 'tronesa'

const gifts = ["juego", "puzzle"];
const materials = "jlepuz";

manufacture(gifts, materials); // ["puzzle"]

const gifts = ["libro", "ps5"];
const materials = "psli";

manufacture(gifts, materials); // []

Solution:

function manufacture(gifts, materials) {
  const regex = new RegExp(`^[${materials}]+${"$"}`);
  return gifts.filter(regex.test.bind(regex));
}

An alternative without RegEx could be using methods like startsWith or indexOf. For example:

function manufacture(gifts, materials) {
  return gifts.filter((gift) =>
    materials.split("").every((material) => gift.includes(material))
  );
}

This function takes care of filtering the gifts with the available materials!

3: The Naughty Elf

Task:

In Santa’s workshop, a naughty elf has been playing with the toy production line, adding or removing an unplanned step.

You have the original sequence of steps in the original manufacturing and the modified sequence that can include an extra step or be missing a step.

Your task is to write a function that identifies and returns the first extra step that was added or removed in the manufacturing chain. If there is no difference between the sequences, return an empty string.

const original = "abcd";
const modified = "abcde";
findNaughtyStep(original, modified); // 'e'

const original = "stepfor";
const modified = "stepor";
findNaughtyStep(original, modified); // 'f'

const original = "abcde";
const modified = "abcde";
findNaughtyStep(original, modified); // ''

Keep in mind:

Solution:

function findNaughtyStep(original, modified) {
  const [lessWords, mostWords] = [original, modified].sort((a, b) =>
    a.length - b.length
  );
  return [...mostWords].find((x, i) => lessWords[i] != x) ?? "";
}

4: Reverse the Parentheses

Task:

In Santa’s workshop 🎅, some Christmas messages have been written in a peculiar way: the letters inside parentheses should be read backwards

Santa needs these messages to be properly formatted. Your task is to write a function that takes a text string and reverses the characters inside each pair of parentheses, removing the parentheses in the final message.

However, keep in mind that there can be nested parentheses, so you should reverse the characters in the correct order.

const a = decode('hola (odnum)') console.log(a) // hola mundo

const b = decode('(olleh) (dlrow)!') console.log(b) // hello world!

const c = decode('sa(u(cla)atn)s') console.log(c) // santaclaus

// Step by step:
// 1. Reverse the nested -> sa(ualcatn)s
// 2. Reverse what's left -> santaclaus

Notes:

Solution:

function decode(message) {
  while (message.includes("(")) {
    const startIndex = message.lastIndexOf("(");
    const endIndex = message.indexOf(")", startIndex);

    const start = message.slice(0, startIndex);
    const middle = [...message.slice(startIndex + 1, endIndex)].reverse();
    const end = message.slice(endIndex + 1, message.length);
    message = start + middle.join("") + end;
  }
  return message;
}

5: Santa’s Cybertruck

Task:

Santa 🎅 is testing his new electric sleigh, the CyberReindeer, on a North Pole road. The road is represented by a string of characters, where:

Example road: S...|....|.....

Each unit of time, the sleigh advances one position to the right. If it encounters a closed barrier, it stops until the barrier opens. If it’s open, it goes straight through.

All barriers start closed, but after 5 units of time, they all open forever.

Create a function that simulates the sleigh’s movement for a given time and returns an array of strings representing the state of the road at each unit of time:

const road = 'S..|...|..' const time = 10 // time units const result =
cyberReindeer(road, time)

/* -> result: [ 'S..|...|..',
// initial state '.S.|...|..',
// sleigh advances on the road '..S|...|..',
// sleigh advances on the road '..S|...|..',
// sleigh stops at the barrier '..S|...|..',
// sleigh stops at the barrier '...S..._..',
// barrier opens, sleigh advances '..._S.._..',
// sleigh advances on the road '..._.S._..',
// sleigh advances on the road '..._..S*..',
// sleigh advances on the road '...*...S..',
// advances through the open barrier] */

The result is an array where each element shows the road at each unit of time.

Keep in mind that if the sleigh is in the same position as a barrier, then it takes its place in the array.

The elves were inspired by this Code Wars challenge.

Solution:

function cyberReindeer(road, time) {
  let s = 0;
  const result = [road];
  road = road.replace("S", ".");

  const roadString = {
    5: road.replaceAll("|", "*"),
  };

  const roadDelay = {
    ".": 1,
    "*": 1,
    "|": 0,
  };

  for (let i = 1; i < time; i++) {
    road = roadString[i] ?? road;
    s += roadDelay[road[s + 1]];
    result.push(
      `${road.substring(0, s)}S${road.substring(s + 1)}`,
    );
  }
  return result;
}