Home

/rwc

a-rendezvous-with-cassidoo.md

markdown
## Rendezvous with Cassidoo Solutions

Solutions to the interview question of the week from the [rendezvous with cassidoo newsletter](https://buttondown.email/cassidoo)

Solutions in the following languages:
- TypeScript
- Elixir

Inspired and forked from [jda0](https://gist.github.com/jda0/01070831825ed63efcd1f626653a16a3)

p155.ts

typescript
/**
 * Sort an array of strings based on the number of distinct
 * characters that occur in the word (followed by the
 * length of the word).
 *
 * $ charNumSort([“Bananas”, “do”, “not”, “grow”, “in”, “Mississippi”])
 * $ do in not Mississippi Bananas grow
 *
 */

const charNumSort = (input: Array<string>) =>
  input
    .sort((first, second) => {
      // use Set() to find unique char count
      const compare = [...new Set(first)].length - [...new Set(second)].length;

      return compare ? compare : second.length - first.length;
    })
    .join(" ");

console.log(charNumSort(["Bananas", "do", "not", "grow", "in", "Mississippi"]));

// https://codesandbox.io/s/modest-sanderson-wxs33?file=/src/index.ts

p157.ts

typescript
/**
 * Given an array of random integers, move all the zeros in the array to the end of the array.
 * Try to keep this in O(n) time (or better)!
 * Example:
 * $ moveZeros([1, 2, 0, 1, 0, 0, 3, 6])
 * $ [1, 2, 1, 3, 6, 0, 0, 0]
 */

const moveZeros = (arr: Array<number>) => {
  let numberOfZeroes = 0;
  const result = arr.reduce((agg, curr) => {
    curr ? agg.push(curr) : numberOfZeroes++;
    return agg;
  }, [] as number[]);

  return [...result, ...Array(numberOfZeroes).fill(0)];
};

console.log(moveZeros([1, 2, 0, 1, 0, 0, 3, 6]));
  
// https://codesandbox.io/s/misty-forest-pxdog?file=/src/index.ts

p158.ts

typescript
/**
 * Given a string s and a character c, return the number of occurrences of c in s.
 * Example:
 *
 * $ numChars(‘oh heavens’, ‘h’)
 * $ 2
 */

const numChars = (input: string, char: string) =>
  /**
   * yay regular expressions! global flag since we wanna count *all* instances
   * return 0 in case of no matches
   */
  (input.match(RegExp(char, "g")) || []).length;

console.log(numChars("oh heavens", "h"));

// https://codesandbox.io/s/mystifying-swirles-8h5it?file=/src/index.ts

p159.ts

typescript
/**
 * Given an array of numbers that represent stock prices (where each number is the price for
 * a certain day), find 2 days when you should buy and sell your stock for the highest profit.
 * Example:
 *
 * $ stockBuySell([110, 180, 260, 40, 310, 535, 695])
 * $ “buy on day 4, sell on day 7”
 */

const stockBuySell = (prices: Array<number>) =>
  `buy on day ${prices.indexOf(Math.min(...prices)) + 1}\
, sell on day ${prices.indexOf(Math.max(...prices)) + 1}`;

// A much faster (the earlier one is ~88% slower, https://jsbench.me/54keiiwuvy/1) way
const stockBuySellReduce = (prices: Array<number>) => {
  const minMax = prices.reduce(
    (agg, curr, index, arr) => {
      if (curr < arr[agg.min]) agg.min = index;
      else if (curr > arr[agg.max]) agg.max = index;
      return agg;
    },
    { min: 0, max: 0 }
  );
  return `buy on day ${minMax.min + 1}, sell on day ${minMax.max + 1}`;
};

console.log(stockBuySell([110, 180, 260, 40, 310, 535, 695]));
console.log(stockBuySellReduce([110, 180, 260, 40, 310, 535, 695]));

// https://codesandbox.io/s/sharp-jepsen-8npl1?file=/src/index.ts

p163.ts

typescript
/**
 * Given an array of people objects (where each person has a name
 * and a number of pizza slices they’re hungry for) and a number
 * for the number of slices that the pizza can be sliced into, return
 * the number of pizzas you need to buy.
 *
 * $ arr = [{ name: Joe, num: 9 }, { name: Cami, num: 3 }, { name: Cassidy, num: 4 }]
 * $ gimmePizza(arr, 8)
 * $ 2 // 16 slices needed, pizzas can be sliced into 8 pieces, so 2 pizzas should be ordered
 */

type TPeopleSlicesMap = {
	name: string;
	num: number;
};
const gimmePizza = (arr: Array<TPeopleSlicesMap>, maxSlices: number) => {
	const totalSlices = arr.reduce((total, { num }) => {
		return (total += num);
	}, 0);
	return Math.ceil(totalSlices / maxSlices);
};

const inputMap = [
	{ name: "Joe", num: 9 },
	{ name: "Cami", num: 3 },
	{ name: "Cassidy", num: 4 }
];
console.log(gimmePizza(inputMap, 8));

// https://codesandbox.io/s/young-darkness-61nq3?file=/src/index.ts

p171.ts

typescript
/**
 * Given a positive integer n, write a function that returns
 * true if it is a perfect square and false otherwise.
 * Don’t use any built-in math functions like sqrt.
 * Hint: Use binary search!
 *
 * Examples:
 * $ perfectSquare(25)
 * $ true
 *
 * $ perfectSquare(10)
 * $ false
 */

const isPerfectSquare = (input: number) => {
	const binarySearchPerfectSquare = (
		input: number,
		start: number,
		end: number
	): number | boolean => {
		if (start > end) return false;

		// mid value, parsed to an int using bitwise operator
		const mid = ((start + end) / 2) >> 0;
		if (mid * mid < input)
			return binarySearchPerfectSquare(input, mid + 1, end);
		if (mid * mid > input)
			return binarySearchPerfectSquare(input, start, mid - 1);
		// mid*mid === input, perfect square!
		return true;
	};
	return binarySearchPerfectSquare(input, 1, input);
};

console.log(isPerfectSquare(25));
console.log(isPerfectSquare(10));

// https://codesandbox.io/s/relaxed-pine-yofdz?file=/src/index.ts

p172.ts

typescript
/**
 * Given an array of integers and a target value, return the number of
 * pairs of array elements that have a difference equal to a target value.
 *
 * Example:
 * $ arrayDiff([1, 2, 3, 4], 1)
 * $ 3 // 2 - 1 = 1, 3 - 2 = 1, and 4 - 3 = 1
 */

const arrayDiff = (arr: Array<number>, target: number) => {
	let count = 0,
		flag = false;

	arr.sort()
		.reverse()
		.forEach((baseNum, i, reverseSortedArr) => {
			if (i === arr.length) return;
			flag = false;
			reverseSortedArr.slice(i + 1).forEach((num, j) => {
				// arr is sorted, so we won't get the target diff again
				if (flag) return;
				if (j === reverseSortedArr.length) return;
				if (baseNum - num === target) {
					count += 1;
					flag = true;
				}
			});
		});
	return count;
};

console.log(arrayDiff([1, 2, 3, 4], 1));

// https://codesandbox.io/s/cool-satoshi-84ku4?file=/src/index.ts

p176.ts

typescript
/**
 * You’re given a string of characters that are only 2s and 0s. Return the
 * index of the first occurrence of “2020” without using the indexOf (or
 * similar) function, and -1 if it’s not found in the string.
 *
 * Example:
 * $ find2020(‘2220000202220020200’)
 * $ 14
 */

const find2020 = (input: string) => {
	let index = -1;
	input.split("").reduce((_shouldBe2020, _curr, i) => {
		const next4 = input.slice(i, i + 4);
		if (next4 === "2020") index = i;
		return next4;
  }, input.slice(0, 4));
  return index;
};

// https://codesandbox.io/s/sharp-mountain-wddiy?file=/src/index.ts

p187.ts

typescript
/**
 * Given a rowIndex, return an array of the values in that
 * row of Pascal’s Triangle.
 */

const getCurrentRow = (previousRow: Array<number>): Array<number> => {
  return Array.from(Array(previousRow.length + 1)).map((_, i) => {
    if (i === 0) return 1;
    else if (i === previousRow.length) return 1;
    else return previousRow[i - 1] + previousRow[i];
  });
};

const getPascalRow = (index: number): Array<number> => {
  if (index === 0) return [1];
  return getCurrentRow(getPascalRow(index - 1));
};

console.log(getPascalRow(0)); // [1]
console.log(getPascalRow(1)); // [1, 1]
console.log(getPascalRow(2)); // [1, 2, 1]
console.log(getPascalRow(3)); // [1, 3, 3, 1]
console.log(getPascalRow(4)); // [1, 4, 6, 4, 1]
  
// https://codesandbox.io/s/heuristic-wood-qzzbd?file=/src/index.ts

p195.ts

typescript
/**
 * Given an integer n, return true if n^3 and n have the same set of digits.
 * Example:
 *
 * $ sameDigits(1) // true
 * $ sameDigits(10) // true
 * $ sameDigits(251894) // true
 * $ sameDigits(251895) // false
 */

const INPUTS = [1, 10, 251894, 251895];

const getUniqueDigitsAsString = (input: number) =>
  [...new Set(input.toString().split("").sort())].join();

const sameDigits = (input: number) => {
  const inputDigits = getUniqueDigitsAsString(input);
  const cubeDigits = getUniqueDigitsAsString(Math.pow(input, 3));
  return inputDigits === cubeDigits;
};

INPUTS.forEach(input => console.log(sameDigits(input)))
// true, true, true, false

// https://codesandbox.io/s/cold-cdn-85qcb?file=/src/index.ts

p198.ts

typescript
/**
 * Given a list, return a list of all its prefixes in ascending order of their
 * length. You’re essentially implementing the inits function in Haskell!
 *
 * Example:
 * $ inits([4, 3, 2, 1])
 * $ [[], [4], [4,3], [4,3,2], [4,3,2,1]]
 *
 * $ inits([144])
 * $ [[], [144]]
 */

const INPUT = [4, 3, 2, 1];

const inits = (input: Array<number>) =>
  input.reduce(
    (arr, curr, index) => {
      arr.push([...arr[index], curr]);
      return arr;
    },
    [[]] as number[][]
  );

console.log(inits(INPUT));

// https://codesandbox.io/s/determined-swanson-qn27b?file=/src/index.ts

p200.ts

typescript
/**
 * Given a direction and a number of columns, write a function that outputs an 
 * arrow of asterisks (see the pattern in the examples below)!
 * 
 * Example:
 * 
 * $ printArrow('right', 3)
 * Output:

*
 *
  *
 *
*

 * $ printArrow('left', 5)
 * Output:

    *
   *
  *
 *
*
 *
  *
   *
    *

 */

const printArrow = (direction: "right" | "left", len: number) => {
  Array.from(Array(2 * (len - 1) + 1)).forEach((_, index) => {
    let numSpaces;
    if (direction === "right") {
      numSpaces = index > len - 1 ? 2 * len - 2 - index : index;
    } else {
      numSpaces = len - (index > len - 1 ? 2 * len - 1 - index : index + 1);
    }
    console.log(`${" ".repeat(numSpaces)}*`);
  });
};

// https://codesandbox.io/s/gifted-perlman-0yvo0?file=/src/index.ts

p202.ts

typescript
const LINE = "".repeat(10);
const PRIDE_COLORS = [
  "#e40303",
  "#ff8c00",
  "#ffed00",
  "#008026",
  "#004dff",
  "#750787"
];

const PrideFlag = () => {
  PRIDE_COLORS.forEach((color) => {
    console.log(`%c${LINE}`, `color: ${color}`);
  });
};

PrideFlag();

// https://codesandbox.io/s/blissful-leavitt-86k1s?file=/src/index.ts

p211.ts

typescript
/**
 * Write a function to find the longest common prefix string in an array of
 * strings.
 *
 * Example:
 *
 * $ longestPrefix(["cranberry","crawfish","crap"])
 * $ "cra"
 *
 * $ longestPrefix(["parrot", "poodle", "fish"])
 * $ ""
 */

function longestPrefix(input: Array<string>) {
  let result = "";

  input[0].split("").reduce((prefix, currentLetter) => {
    const isPrefixValid = input.every((word) => word.startsWith(prefix));
    if (isPrefixValid) {
      result = prefix;
      return `${prefix}${currentLetter}`;
    }
    return result;
  }, "");
  return result;
}

// https://codesandbox.io/s/heuristic-dan-pl0nn?file=/src/index.ts

p217.ts

typescript
/**
 * An “odious number” is a non-negative number that has an 
 * odd number of 1s in its binary expansion. Write a 
 * function that returns true if a given number is odious.
 * 
 * Example:
 * 
 * $ isOdious(14)
 * $ true
 * 
 * $ isOdious(5)
 * $ false
 */

const isOdious = (input: number) =>
  (input.toString(2).match(/1/g) ?? []).length % 2 === 1;

// https://codesandbox.io/s/admiring-poitras-8l6sd?file=/src/index.ts

p218.ts

typescript
/**
 * Given an array of objects A, and an array of indexes B,
 * reorder the objects in array A with the given indexes
 * in array B.
 *
 * Example:
 *
 * let a = [C, D, E, F, G, H];
 * let b = [3, 0, 4, 1, 2, 5];
 *
 * $ reorder(a, b) // a is now [D, F, G, C, E, H]
 */

const reorder = (
  a: Array<Record<string, unknown> | string>,
  b: Array<number>
) =>
  [...Array(a.length)].reduce((res, _, index) => {
    res[b[index]] = a[index];
    return res;
  }, []);

// https://codesandbox.io/s/agitated-bash-tmu25?file=/src/index.ts

p259.ex

elixir
defmodule RWC_259 do
  @doc """
  Given an integer n, count the total number of 1 digits appearing in all 
  non-negative integers less than or equal to n.

  Example:

  > numberOfOnes(14)
  > 7 // 1, 10, 11, 12, 13, 14
  """
  defp count_one_recursively(input, count) when input == 1, do: count + 1

  defp count_one_recursively(input, count) do
    input
    |> Integer.to_string()
    |> String.split("")
    |> Enum.count(&(&1 == "1"))
    |> then(fn x ->
      case x > 0 do
        true ->
          count_one_recursively(input - 1, count + x)

        _ ->
          count_one_recursively(input - 1, count)
      end
    end)
  end

  def number_of_ones(input) do
    input
    |> count_one_recursively(0)
    |> IO.puts()
  end
end

RWC_259.number_of_ones(14)

p270.ex

elixir
defmodule RWC_270 do
  @doc """
  Let’s say you have n doors that start out as closed. With the first pass 
  across the doors, you toggle every door open. With the second pass, you 
  toggle every second door. With the third, every third door, and so on. 
  Write a function that takes in an integer numberOfPasses, and returns how 
  many doors are open after the number of passes.

  Example:

  let n = 7
  let numberOfPasses = 3

  > passDoors(n, numberOfPasses)
  > 4

  // Explanation:
  // 0 means open, 1 means closed
  // Initial: 1 1 1 1 1 1 1
  // Pass 1:  0 0 0 0 0 0 0
  // Pass 2:  0 1 0 1 0 1 0
  // Pass 3:  0 1 1 1 0 0 0
  """
  @spec pass_doors(n :: non_neg_integer, number_of_passes :: non_neg_integer) :: non_neg_integer
  def pass_doors(n, number_of_passes) do
    1..number_of_passes
    # duplicate with n+1 because map_every/3 starts from first elem indexed 0 
    # open => true, closed => false
    |> Enum.reduce(List.duplicate(false, n + 1), fn nth, doors ->
      Enum.map_every(doors, nth, &(not &1))
    end)
    # ignore the extra door we added at the start
    |> Enum.drop(1)
    |> Enum.count(& &1)
  end
end

RWC_270.pass_doors(7, 3)

p281.ex

elixir
defmodule RWC_281 do
  @doc """
  Given an array of integers arr and an integer n, return a subarray 
  of arr of length n where the sum is the largest. 

  Make sure you maintain the order of the original array, and if n 
  is greater than arr.length, you can choose what you want to return.

  > maxSubarray([-4,2,-5,1,2,3,6,-5,1], 4)
  > [1,2,3,6]

  > maxSubarray([1,2,0,5], 2)
  > [0,5]
  """

  def maxSubarray(input, size) do
    input
    |> Enum.chunk_every(size, 1, :discard)
    |> Enum.max_by(&Enum.sum(&1))
  end
end

IO.inspect(RWC_281.maxSubarray([-4, 2, -5, 1, 2, 3, 6, -5, 1], 4))
IO.inspect(RWC_281.maxSubarray([1, 2, 0, 5], 2))

p282.ex

elixir
defmodule RWC_282 do
  @doc """
  Given a number, sum every second digit in that number. 

  Example: 

  > sumEveryOther(548915381)
  > 26 // 4+9+5+8

  > sumEveryOther(10)
  > 0 

  > sumEveryOther(1010.11)
  > 1 // 0+0+1
  """

  def sumEveryOther(input) do
    input
    |> to_string()
    |> String.graphemes()
    |> List.delete_at(0)
    |> Enum.filter(&(&1 !== "."))
    |> Enum.take_every(2)
    |> Enum.map(&String.to_integer/1)
    |> Enum.sum()
  end
end

p284.ex

elixir
defmodule RWC_284 do
  @doc """
  You are given a list of positive integers which represents some 
  range of integers which has been truncated. Find the missing bits, 
  insert ellipses to show that that part has been truncated, and 
  print it. If the consecutive values differ by exactly two, 
  then insert the missing value.

  Examples:

  > missingBits([1,2,3,4,20,21,22,23])
  > "[1,2,3,4,...,20,21,22,23]"

  > missingBits([1,2,3,5,6])
  > "[1,2,3,4,5,6]"

  > missingBits([1,3,20,27])
  > "[1,2,3,...,20,...,27]"
  """

  def missingBits(input) do
    input
    |> Enum.with_index()
    |> then(fn input_with_index ->
      input_with_index
      |> Enum.reduce([], fn {num, index}, acc ->
        {next_num, _} = Enum.at(input_with_index, index + 1, {num, nil})

        case next_num - num do
          # Last index
          0 -> [num | acc]
          1 -> [num | acc]
          # When step is exactly two
          2 -> [num + 1, num | acc]
          _ -> ["...", num | acc]
        end
      end)
      |> Enum.reverse()
      |> Enum.join(",")
      |> then(&"[#{&1}]")
    end)
  end
end

p285.ex

elixir
defmodule RWC_285 do
  @doc """
  Given a positive integer, generate an array in which every 
  element is an array that goes from 1 to the index of that array.

  Example:

  > generateArrays(4)
  > [[1], [1, 2], [1, 2, 3], [1, 2, 3, 4]]

  > generateArrays(1)
  > [[1]]
  """

  def generateArrays(input) do
    1..input
    |> Enum.to_list()
    |> Enum.map(&Enum.to_list(1..&1))
  end
end

p286.ex

elixir
defmodule RWC_286 do
  @doc """
  Spreadsheet programs often use the A1 Reference Style to refer to columns. 
  Given a column name in this style, return its column number.

  Examples of column names to their numbers:

  A -> 1
  B -> 2
  C -> 3
  // etc
  Z -> 26
  AA -> 27
  AB -> 28 
  // etc
  AAA -> 703
  """

  def get_weight(char, power) do
    char
    |> String.to_charlist()
    |> hd()
    # A => 65, B => 66, so on...
    |> then(&(&1 - 64))
    |> then(&(&1 * 26 ** power))
  end

  def recusively_get_weight([{char, index}]), do: get_weight(char, index)
  def recusively_get_weight([left | rest]),
    do: recusively_get_weight([left]) + recusively_get_weight(rest)

  def get_column_number(input) do
    input
    |> String.split("", trim: true)
    |> Enum.reverse()
    |> Enum.with_index()
    |> recusively_get_weight()
  end
end

p287.ex

elixir
defmodule RWC_287 do
  @doc """
  Print the digits 0 through 100 without using the characters 
  1, 2, 3, 4, 5, 6, 7, 8, or 9 in your code. Get creative!
  """

  def print_digits() do
    hundred =
      "d"
      |> to_charlist()
      |> hd()

    zero =
      [hundred - hundred]
      |> hd()

    zero..hundred
    |> Enum.join(", ")
  end
end

p288.ex

elixir
defmodule RWC_288 do
  @doc """
  Given a string of parenthesis, return the number of parenthesis 
  you need to add to the string in order for it to be balanced.

  Examples:

  > numBalanced(`()`)
  > 0

  > numBalanced(`(()`)
  > 1

  > numBalanced(`))()))))()`)
  > 6

  > numBalanced(`)))))`)
  > 5
  """

  def num_balanced(input) do
    input
    |> String.split("", trim: true)
    |> Enum.frequencies()
    |> Map.values()
    |> then(
      &case &1 do
        [only_one_kind] -> only_one_kind
        [one, other] -> abs(one - other)
      end
    )
  end
end

p289.ex

elixir
defmodule RWC_289 do
  @doc """
  Given a list of numbers, return all groups of repeating consecutive numbers.

  Examples:

  > repeatedGroups([1, 2, 2, 4, 5])
  [[2, 2]]

  > repeatedGroups([1, 1, 0, 0, 8, 4, 4, 4, 3, 2, 1, 9, 9])
  [[1, 1], [0, 0], [4, 4, 4], [9, 9]]
  """

  def chunk_repeats([head | rest]), do: chunk_repeats(rest, [[head]])
  def chunk_repeats([], done), do: done

  def chunk_repeats([head | rest], [[head | head_repeated] | previously_repeated]),
    do: chunk_repeats(rest, [[head | [head | head_repeated]] | previously_repeated])

  def chunk_repeats([head | rest], previously_repeated),
    do: chunk_repeats(rest, [[head] | previously_repeated])

  def repeated_groups(input) do
    input
    |> chunk_repeats()
    |> Enum.reverse()
    |> Enum.filter(&(length(&1) > 1))
  end
end

p300.ex

elixir
defmodule RWC_300 do
  @doc """
  Write a function to find out whether the binary representation of 
  a number is palindrome or not.

  Example:

  > binaryPal(5)
  > true

  > binaryPal(10)
  > false
  """

  def binary_pal(input) do
    input
    |> Integer.to_charlist(2)
    |> List.to_string()
    |> then(fn digits ->
      digits
      |> String.reverse()
      |> then(
        &case &1 do
          ^digits -> true
          _ -> false
        end
      )
    end)
  end
end

p301.ex

elixir
defmodule RWC_301 do
  @doc """
  Given a string, calculate the score that it would get in a game of Scrabble.
  For extra credit, try verifying if the string is a valid word, or take into 
  account premium squares!

  Scoring and example:

  1 point: E, A, I, O, N, R, T, L, S, U
  2 points: D, G
  3 points: B, C, M, P
  4 points: F, H, V, W, Y
  5 points: K
  8 points: J, X
  10 points: Q, Z

  > scrabbleScore('FIZZBUZZ')
  > 49
  """

  @score_map %{
    "EAIONRTLSU" => 1,
    "DG" => 2,
    "BCMP" => 3,
    "FHVWY" => 4,
    "K" => 5,
    "JX" => 8,
    "QZ" => 10
  }

  def scrabble_score(input) do
    input
    |> String.split("", trim: true)
    |> Enum.reduce(0, fn letter, score ->
      @score_map
      |> Map.keys()
      |> Enum.find(&String.contains?(&1, letter))
      |> then(&Map.get(@score_map, &1))
      |> Kernel.+(score)
    end)
  end
end

p303.ex

elixir
defmodule RWC_303 do
  @doc """
  Given an array of people objects (where each person has a name and a number of 
  pie pieces they’re hungry for) and a number for the number of pieces that the 
  pie can be cut into, return the number of pies you need to buy.

  Example:

  iex> 
  ...>  arr = [
  ...>    %{ name: Joe, num: 9 }, 
  ...>    %{ name: Cami, num: 3 }, 
  ...>    %{ name: Cassidy, num: 4 }
  ...>  ]
  iex> RWC_303.num_pie(arr, 8)
  2 # 16 pieces needed, pies can be cut into 8 pieces, so 2 pies should be bought
  """

  def num_pie(input, count) do
    input
    |> Enum.reduce(0, &(&2 + &1[:num]))
    |> div(count)
  end
end

p304.ex

elixir
defmodule RWC_304 do
  @doc """
  Given an array arr and integers n and m, remove n elements 
  from the front of the array, and m elements from the back. 
  Assume that n + m <= arr.length.

  Example:

  iex> RWC_304.trim_array([1, 2, 3, 4, 5, 6], 2, 1)
  [3, 4, 5]

  iex> RWC_304.trim_array([6, 2, 4, 3, 7, 1, 3], 5, 0)
  [1, 3]

  iex> RWC_304.trim_array([1, 7], 0, 0)
  [1, 7]
  """

  def trim_array(input, n, m) do
    input
    |> Enum.slice(n, length(input) - n - m)
  end
end

p305.ex

elixir
defmodule RWC_305 do
	@doc """
	Given some JSON data, calculate the maximum depth reached. Both arrays 
	and dictionaries increase the depth! If the input is invalid data, the 
	response should be undefined (you decide how you want that to return).

	iex> RWC_305.depth_json([])
	1

	iex> RWC_305.depth_json([1, 2, 3, 4, 5])
	1

	iex> RWC_305.depth_json([%{a: []}, ["abc"]])
	3
	"""
	def depth_json(input), do: compute_depth(input)

	defp compute_depth(input) when is_list(input) or is_map(input) do
		cond do
			is_list(input) and input == [] ->
				1

			true ->
				input
				|> flatten_if_map()
				|> Enum.map(&compute_depth/1)
				|> Enum.max()
				|> Kernel.+(1)
		end
	end

	defp compute_depth(_), do: 0

	defp flatten_if_map(input) when is_map(input), do: Map.values(input)
	defp flatten_if_map(input), do: input
end

p306.ex

elixir
defmodule RWC_306 do
  @doc """
  Write a function that takes an array of consecutive, increasing letters as input, 
  and returns any missing letters in the array between the first and last letter.

  Example:

  iex> RWC_306.missing_letters(["a","b","c","d","f"])
  ["e"]


  iex> RWC_306.missing_letters(["a","b","c","d","e","h","i","j","k","l","m","n","o",
  ...> "p","q","r","s","t","u","w","x","y","z"])
  ["f","g","v"]
  """

  def missing_letters(input) do
    input_complete_mapset =
      input
      |> then(fn list ->
        [head | _] = list
        tail = List.last(list)

        hd(to_charlist(head))..hd(to_charlist(tail))
        |> MapSet.new()
      end)

    input_mapset =
      input
      |> MapSet.new(&hd(to_charlist(&1)))

    input_complete_mapset
    |> MapSet.difference(input_mapset)
    |> MapSet.to_list()
    |> List.to_string()
    |> String.graphemes()
  end
end

p307.ex

elixir
defmodule RWC_307 do
  @doc """
  Given an integer n, return true if it's a perfect
  square AND when reversed, is still a perfect square.


  iex> RWC_307.reversed_squares(9)
  true

  iex> RWC_307.reversed_squares(441)
  true

  iex> RWC_307.reversed_squares(25)
  false
  """

  def reversed_squares(input) do
    input
    |> Integer.digits()
    |> Enum.reverse()
    |> Integer.undigits()
    |> then(
      &cond do
        is_perfect_square(&1) and is_perfect_square(input) -> true
        true -> false
      end
    )
  end

  defp is_perfect_square(input) do
    input
    |> :math.sqrt()
    |> then(&if Kernel.trunc(&1) == &1, do: true, else: false)
  end
end

p308.ex

elixir
defmodule RWC_308 do
  @doc """
  Given an array of strings and a max width, format the text such that each line has exactly 
  maxWidth characters and is fully justified. You can choose how you want to wrap a word.

  Example:

  iex> RWC_308.justify_text(["This", "is", "an", "example", "of", "text", "justification."], 16)
  [
    "This    is    an",
    "example  of text",
    "justification.  "
  ]
  """

  def justify_text(input, max_length) do
    input
    |> Enum.reduce([[]], fn word, phrase_list ->
      phrase_list
      |> List.last([])
      |> then(fn last_phrase ->
        current_phrase_length = last_phrase |> Enum.join(".") |> String.length()

        cond do
          current_phrase_length + String.length(word) < max_length ->
            # update last element
            last_list =
              phrase_list
              |> Enum.at(-1)
              |> Enum.concat([word])

            phrase_list
            |> Enum.drop(-1)
            |> Enum.concat([last_list])

          true ->
            # move to new phrase
            phrase_list
            |> Enum.concat([[word]])
        end
      end)
    end)
    |> Enum.map(&justify_phrase(&1, max_length))
  end

  defp justify_phrase(input, max_length) do
    number_of_spaces_to_add = max_length - (input |> Enum.join("") |> String.length())
    number_of_breaks = if length(input) == 1, do: 1, else: length(input) - 1
    each_space_block_length = div(number_of_spaces_to_add, number_of_breaks)
    remainder = rem(number_of_spaces_to_add, number_of_breaks)

    spaces_list =
      " "
      |> list_from(each_space_block_length)
      |> list_from(number_of_breaks)
      |> then(fn [first_break_spaces | rest] ->
        case remainder do
          0 ->
            [first_break_spaces | rest]

          _ ->
            first_break_spaces
            |> Enum.concat(list_from(" ", remainder))
            |> then(&[&1 | rest])
        end
      end)
      |> then(
        &cond do
          length(input) == 1 -> &1
          true -> Enum.concat(&1, [[""]])
        end
      )

    input
    |> Enum.zip(spaces_list)
    |> Enum.reduce("", fn {word, spaces}, line ->
      "#{line}#{word}#{Enum.join(spaces)}"
    end)
  end

  defp list_from(el, count), do: for(_ <- 1..count, do: el)
end

p309.ex

elixir
defmodule RWC_309 do
  @doc """
  Given a string, separate it into groups of non-space equal characters, sorted.

  Example:

  iex> RWC_309.explode_string("Ahh, abracadabra!")
  ["!",",","A","aaaaa","bb","c","d","hh","rr"]
  """

  def explode_string(input) do
    input
    |> String.replace(" ", "")
    |> String.split("", trim: true)
    |> Enum.frequencies()
    |> Map.to_list()
    |> Enum.map(fn {char, count} ->
      list_from(char, count)
      |> Enum.join()
    end)
  end

  defp list_from(el, count), do: for(_ <- 1..count, do: el)
end

p310.ex

elixir
defmodule RWC_310 do
  @doc """
  Given an array where each element is the price of a given stock on that index's day, 
  choose a single day to buy a stock and a different day (in the future/later in the array) 
  to sell the stock to maximize your profit. Return the maximum profit that you can get 
  from a given input. If you can't profit, return 0.

  Example:

  iex> RWC_310.maximum_profit([7, 1, 5, 3, 6, 4])
  5    # Buy on day 2, and sell on day 5, your profit = 6 - 1 = 5.
  """

  def maximum_profit(input) do
    input
    |> Enum.with_index()
    |> Enum.reduce(0, fn {price, index}, max_profit ->
      input
      |> Enum.slice((index + 1)..-1)
      |> Enum.max(&>=/2, fn -> 0 end)
      |> Kernel.-(price)
      |> then(
        &cond do
          &1 > max_profit -> &1
          true -> max_profit
        end
      )
    end)
  end
end

p311.ex

elixir
defmodule RWC_311 do
  @doc """
  Given two strings s and t, return true if t is an anagram of s, and false otherwise. 
  Try this in a language you're not comfortable with!

  Example:

  iex> RWC_311.is_anagram("barbie", "oppenheimer")
  false

  iex> RWC_311.is_anagram("race", "care")
  true
  """

  def is_anagram(a, b), do: get_chars(a) === get_chars(b)

  defp get_chars(input), do: input |> String.split("", trim: true) |> Enum.frequencies()
end

p312.ex

elixir
defmodule RWC_312 do
  @doc """
  Implement the Luhn algorithm to validate a credit card number.
  Bonus points if you can identify what brand of credit card the user inputted!

  iex> RWC_312.luhn_check(123456789)
  false

  iex> RWC_312.luhn_check(5555555555554444)
  true
  """

  def luhn_check(input) do
    input
    |> Integer.digits()
    |> Enum.with_index(1)
    |> Enum.reduce(0, fn {digit, index}, sum ->
      cond do
        rem(index, 2) == 0 -> digit * 2
        true -> digit
      end
      |> Integer.digits()
      |> Enum.sum()
      |> Kernel.+(sum)
    end)
    |> then(&(rem(&1, 10) == 0))
  end
end

p313.ex

elixir
defmodule RWC_313 do
  @doc """
  You have a faulty keyboard. Whenever you type a vowel on it (a,e,i,o,u,y), 
  it reverses the string that you have written, instead of typing the character.
  Typing other characters works as expected. Given a string, return what will be 
  on the screen after typing with your faulty keyboard.

  Example:

  iex> RWC_313.faulty_keeb("string")
  "rtsng"

  iex> RWC_313.faulty_keeb("hello world!")
  "w hllrld!"
  """

  @vowels ["a", "e", "i", "o", "u", "y"]

  def faulty_keeb(input) do
    input
    |> String.graphemes()
    |> Enum.reduce([], fn char, word ->
      cond do
        Enum.member?(@vowels, char) -> Enum.reverse(word)
        true -> Enum.concat(word, [char])
      end
    end)
    |> Enum.join()
  end
end

p314.ex

elixir
defmodule RWC_314 do
  @doc """
  Make a "guessing game" where there is a target number, and as the user makes
  guesses, the output returns higher or lower until the user is correct.

  Example usage:

  Guess the number!
  > 10
  higher
  > 20
  higher
  > 30
  lower
  > 25
  higher
  > 27
  Correct! You won in 5 guesses!
  """

  def solve(guess) do
    IO.puts("Guess the number!")

    input()
    |> solve(guess)
  end

  def solve(guess, answer, guess_count \\ 1)

  def solve(guess, answer, 1) when guess === answer,
    do: IO.puts("Correct! You won in 1 guess!") |> exit()

  def solve(guess, answer, guess_count) when guess === answer,
    do: IO.puts("Correct! You won in #{guess_count} guesses!") |> exit()

  def solve(guess, answer, guess_count) do
    cond do
      guess > answer ->
        IO.puts("lower")

      guess < answer ->
        IO.puts("higher")
    end

    input()
    |> solve(answer, guess_count + 1)
  end

  defp input() do
    IO.gets("> ")
    |> Integer.parse()
    |> then(&elem(&1, 0))
  end
end

RWC_314.solve(:rand.uniform(100))

p315.ex

elixir
defmodule RWC_315 do
  @moduledoc """
  Given a sequence of numbers, generate a "count and say" string.

  Example:

  iex> RWC_315.count_and_say(112222555)
  "two 1s, then four 2s, then three 5s"

  iex> RWC_315.count_and_say(3333333333)
  "ten 3s"
  """

  @number_say_map %{
    1 => "one",
    2 => "two",
    3 => "three",
    4 => "four",
    5 => "five",
    6 => "six",
    7 => "seven",
    8 => "eight",
    9 => "nine",
    10 => "ten"
  }

  def count_and_say(input) do
    input
    |> Integer.digits()
    # count
    |> Enum.reduce([], fn number, list ->
      current_list = List.first(list, [nil])

      current_list
      |> List.first()
      |> then(fn current_digit ->
        case current_digit do
          # same digit as current
          ^number ->
            list
            |> List.delete_at(0)
            |> then(&[[number | current_list] | &1])

          # new digit
          _ ->
            [[number] | list]
        end
      end)
    end)
    |> Enum.reverse()
    # say
    |> Enum.map_join(", then ", fn list ->
      len = Map.get(@number_say_map, length(list))
      "#{len} #{List.first(list)}s"
    end)
  end
end

p316.ex

elixir
defmodule RWC_316 do
  @moduledoc """
  Given an array of integers and a number k (where k is guaranteed to be less 
  than the array's length), return a subarray of length k with the minimum 
  possible sum. Maintain the order of the original array!

  Example:

  iex> RWC_316.min_subs([1, 3, 20, 4, 8, 9, 11], 3)
  [4, 8, 9]

  iex> RWC_316.min_subs([4, 4, 4, 4, 8], 2)
  [4, 4]
  """

  def min_subs(input, len) do
    input
    |> Enum.chunk_every(len, 1, :discard)
    |> Enum.min_by(&Enum.sum/1)
  end
end

p317.ex

elixir
defmodule RWC_317 do
  @moduledoc """
  Given an array of integers, sort them into two separate sorted 
  arrays of even and odd numbers. If you see a zero, skip it.

  Example:

  iex> RWC_317.separate_and_sort([4, 3, 2, 1, 5, 7, 8, 9])
  [[2, 4, 8], [1, 3, 5, 7, 9]]

  iex> RWC_317.separate_and_sort([1,1,1,1])
  [[], [1,1,1,1]]
  """

  def separate_and_sort(input) do
    input
    |> Enum.sort()
    |> Enum.split_with(&(rem(&1, 2) == 0))
    |> Tuple.to_list()
  end
end

p318.ex

elixir
defmodule RWC_318 do
  @moduledoc """
  You have n equal-sized blocks and you want to build a staircase 
  with them. Return the number of steps you can fully build.

  iex> RWC_318.build_staircase(6)
  3

  #=> #
  #=> ##
  #=> ###

  iex> RWC_318.build_staircase(9)
  3 #=> it takes 10 blocks to make 4 steps
  """

  def build_staircase(input) do
    1..input
    |> Enum.reduce_while(0, fn step, total ->
      cond do
        total + step > input -> {:halt, step - 1}
        true -> {:cont, total + step}
      end
    end)
  end
end

p322.ex

elixir
defmodule RWC_322 do
  @moduledoc """
  Given two strings s and t, determine if they are isomorphic. 
  Two strings are isomorphic if there is a one-to-one mapping 
  possible for every character of the first string to every 
  character of the second string.

  iex> RWC_322.is_isomorphic("abb", "cdd")
  true # "a" maps to "c" and "b" maps to "d"

  iex> RWC_322.is_isomorphic("cassidy", "1234567")
  false # "s" cannot have a mapping to both "3" and "4"

  iex> RWC_322.is_isomorphic("cass", "1233")
  true
  """

  def is_isomorphic(first, second) do
    [first, second]
    |> Enum.map(fn string ->
      string
      |> String.split("", trim: true)
      |> Enum.frequencies()
      |> Map.values()
    end)
    |> then(fn [f1, f2] -> f1 == f2 end)
  end
end

p323.ex

elixir
defmodule RWC_323 do
  @moduledoc """
  Given a string s, you are allowed to delete at most k characters. 
  Find if the string can be a palindrome after deleting at most k characters.

  iex> RWC_323.k_pal("abcweca", 2)
  true

  iex> RWC_323.k_pal("abcweca", 1)
  false

  iex> RWC_323.k_pal("acwca", 2)
  true

  iex> RWC_323.k_pal("acxcb", 1)
  false
  """

  def k_pal(string, count) do
    string
    |> String.graphemes()
    |> check_first_and_last_characters(count)
  end

  defp check_first_and_last_characters([_char], _count), do: true
  defp check_first_and_last_characters([char | [char]], _count), do: true

  defp check_first_and_last_characters(string, count) do
    [first | with_last] = string
    [last | remaining_reversed] = Enum.reverse(with_last)
    remaining = Enum.reverse(remaining_reversed)

    cond do
      first == last ->
        check_first_and_last_characters(remaining, count)

      first != last and count == 0 ->
        false

      first != last and count > 0 ->
        check_first_and_last_characters([first | remaining], count - 1) or
          check_first_and_last_characters(with_last, count - 1)

      true ->
        false
    end
  end
end

p325.ex

elixir
defmodule RWC_325 do
  @moduledoc """
  Given a list of words and a dictionary of letter scores, find
  the word with the highest score according to the rules:

  score = word_length * (sum of letter scores in the word)

  If there are multiple words with the same highest score,
  return the lexicographically smallest one.

  iex> word_list = ["apple", "banana", "cherry", "date", "fig"];
  ...> RWC_325.score_word_game(word_list)
  "cherry"
  """

  def score_word_game(word_list, _letter_scores \\ nil) do
    word_list
    |> Enum.map(&get_word_score/1)
    |> Enum.max_by(fn {_word, score} -> score end)
    |> then(&elem(&1, 0))
  end

  defp get_word_score(word) do
    word
    |> String.downcase()
    |> String.graphemes()
    |> Enum.reduce(0, fn letter, total ->
      score = (to_charlist(letter) |> hd()) - 96

      total + score
    end)
    |> then(&{word, &1})
  end
end
👀

Getting page views