Cassidoo Interview question of the week
My answers to the inteview questions from Cassidoo newsletter.
January 2024
You can find here my submissions to the Interview questions of the week from Cassidoo newsletter !
09-09-2024 Minimum number of rows to seat group
You are given an array of people represented by integers, where each number corresponds to the number of people in a group. Determine the minimum number of rows required to seat everyone such that no group is split across different rows. You can assume no group will be larger than a given row size!
const minRows = (groupSizes, rowSize) => {
const rows = [];
for (const size of groupSizes.map(a => a).sort((a, b) => b - a)) {
let foundSpace = false;
for (let i = 0; i < rows.length; i++) {
if (rows[i] + size <= rowSize) {
rows[i] += size;
foundSpace = true;
break;
}
}
if (!foundSpace) {
rows.push(size);
}
}
return rows.length;
}
02-09-2024 Shoe Pair Counter
You are given an array of strings representing a collection of shoes. Each shoe is labeled with its type (“L” for left or “R” for right) and its size. Determine the maximum number of matching pairs of shoes that can be formed.
Size | Left | Right |
---|---|---|
6 | ||
6.5 | ||
7 | ||
7.5 | ||
8 | ||
8.5 | ||
9 |
Pairs Made:
- Size 7: 1 pair(s)
- Size 8: 1 pair(s)
- Size 9: 1 pair(s)
Total Pairs: 3
All Shoes:
function maxPairs(shoes) {
const shoeCounts = {};
let pairs = 0;
for (const shoe of shoes) {
const [type, size] = shoe.split('-');
const oppositeShoe = `${type === 'L' ? 'R' : 'L'}-${size}`;
if (shoeCounts[oppositeShoe]) {
pairs++;
shoeCounts[oppositeShoe]--;
} else {
shoeCounts[shoe] = (shoeCounts[shoe] || 0) + 1;
}
}
return pairs;
}
15-04-2024
Given a string str, write a function to determine the longest substring containing only two unique characters.
const longestSubstrofTwoUniqueChars = (str) => {
if (str.length < 3) {
return str.length
}
let charsByCount = {}
let start = 0
let maxCount = 0;
charsByCount[str[start]] = (charsByCount[str[start]] || 0) + 1;
for (let end = 1; end < str.length; end++) {
charsByCount[str[end]] = (charsByCount[str[end]] || 0) + 1;
while (true) {
if (Object.values(charsByCount).length > 2) {
charsByCount[str[start]] = charsByCount[str[start]] - 1
if (charsByCount[str[start]] === 0) {
delete charsByCount[str[start]]
}
start++
continue
}
break
}
if (end - start + 1 > maxCount) {
maxCount = end - start + 1
}
}
return maxCount
}
08-04-2024
Imagine you have n dice, and each die has m faces on it (so the numbers are from 1 to m). Write a function where, given an integer target, it returns the number of possible ways to roll the dice to get the sum of target face up.
const diceSum = (dies, faces, target) => {
if (target < dies || target > dies * faces) {
return 0;
}
const dp = Array.from({ length: dies + 1 }, () => Array(target + 1).fill(0));
for (let i = 1; i <= faces && i <= target; i++) {
dp[1][i] = 1;
}
for (let dice = 2; dice <= dies; dice++) {
for (let dice_value = 1; dice_value <= target;dice_value++) {
for (let i = 1; i <= faces && i < dice_value; i++) {
dp[dice][dice_value] += dp[dice - 1][dice_value - i];
}
}
}
return dp[dies][target];
}
01-04-2024
Given an array of numbers, add all of the values together but only if the number doesn’t repeat a digit.
function sumUniqueNumbers(arr) {
let sum = 0;
for (let num of arr) {
if (isUnique(num)) {
sum += num;
}
}
return sum;
}
function isUnique(num) {
const numString = num.toString();
const digitSet = new Set();
for (let digit of numString) {
if (digitSet.has(digit)) {
return false;
}
digitSet.add(digit);
}
return true;
}
25-03-2024
Given a 2D array of 0s and 1s, where 0 represents water and 1 represents land, return the size of the largest “island” in the water. Diagonal connections don’t count!
const maxAreaOfIsland = (originalMap) => {
let islandMap = originalMap.map(r => r.map(c => c))
let biggest = 0
for (let i = 0; i < islandMap.length; i++) {
for (let j = 0; j < islandMap[i].length; j++) {
if (islandMap[i][j] === 1) {
biggest = Math.max(biggest, dfs(islandMap, i, j))
}
}
}
return biggest
}
const dfs = (islandMap, x, y) => {
if (x < 0 || x >= islandMap.length || y < 0 || y >= islandMap[0].length || islandMap[x][y] === 0) {
return 0
}
islandMap[x][y] = 0
return 1 + dfs(islandMap, x + 1, y) + dfs(islandMap, x - 1, y) + dfs(islandMap, x, y + 1) + dfs(islandMap, x, y - 1)
}
18-03-2024
Given an integer array, write a function hills(arr) and a function valleys(arr) that return the number of hills and valleys, respectively, in the array.
Hills: 0
Valleys: 0
const hills = (arr) => elevation(arr, false)
const valleys = (arr) => elevation(arr, true)
const elevation = (arr, down) => {
let c = 0
let mark = false
for (let i = 1;i<arr.length;i++) {
if ((down && arr[i] < arr[i-1]) || (!down && arr[i] > arr[i-1]) ) {
mark = true
}
if (mark && ((down && arr[i] > arr[i-1]) || (!down && arr[i] < arr[i-1]))) {
c++
mark = false
}
}
return c
}
11-03-2024
Given an integer array arr, return the maximum difference between two successive elements in arr’s sorted form. Return 0 if there’s 0 or 1 elements.
Max difference for is 0
const maxDiff = (arr) => {
arr.sort((a, b) => a > b)
let max = 0
for (let i = 1;i<arr.length;i++) {
const diff = arr[i] - arr[i-1]
if (diff > max) {
max = diff
}
}
return max
}
04-03-2024
Make a pomodoro timer where a user can start the timer, pause for a set break time, and continue after the break.
Wanted to do some react, not the prettiest code but it works !
Without any Css, here’s the component, the times used for the demo are 5 seconds of work, and 3 seconds of break. It will alternate automatically between the two and you can pause the timer completely if needs be.
import { useState, useEffect } from 'react';
const Timer = () => {
const [state, setState] = useState("")
const [resumeTo, setResumeTo] = useState("")
const [timeLeft, setTimeLeft] = useState(null)
const work = () => {
setState("work")
setTimeLeft(15 * 1000)
}
const breakTime = () => {
setState("break")
setTimeLeft(5 * 1000)
}
const pause = () => {
setResumeTo(state)
setState("pause")
}
useEffect(() => {
const intervalId = setInterval(() => {
if (state !== "pause" && state !== "") {
setTimeLeft((_timespan) => _timespan - 1_000);
}
}, 1_000);
return () => {
clearInterval(intervalId);
};
});
if (state === "work" && timeLeft / 1000 === 0) {
setState("break")
setTimeLeft(3 * 1000)
breakTime()
}
if (state === "break" && timeLeft / 1000 === 0) {
work()
}
const formatTimer = (timeToFormat) => {
const mins = Math.floor(timeToFormat / 60 / 1000)
const secs = (timeToFormat / 1000) - Math.floor(timeToFormat / 60 / 1000)*60
return <span>{String(mins).padStart(2, '0')}:{String(secs).padStart(2, '0')}</span>
}
if (state === "") {
return <button onClick={work} >Start pomodoro</button>
}
return (
<div className="timer">
{ state !== "pause" && <button onClick={pause}>Pause</button>}
{
state === "pause"
? <>
<button onClick={() => setState(resumeTo)}>Resume the {resumeTo}</button>
<div>Time left in {resumeTo} => {formatTimer(timeLeft)} </div>
</>
: <div>{state === "work" ? "Break" : "Work"} in {formatTimer(timeLeft)} </div>
}
</div>
);
};
export default function App() {
return <Timer />
}
26-02-2023
Given a number and a digit to remove from that number, maximize the resulting number after the digit has been removed and print it.
function removeDigit(number, needle) {
haystack = number.toString()
let biggestNumber = 0;
for(let i = 0; i < haystack.length; i++) {
if (haystack[i] === needle.toString()) {
const cleaned = haystack.slice(0, i) + haystack.slice(i+1)
if (parseInt(cleaned) > biggestNumber) {
biggestNumber = parseInt(cleaned)
}
}
}
return biggestNumber === 0 ? number : biggestNumber
}
console.log(removeDigit(31415926, 1)) // 3415926
console.log(removeDigit(1231, 1)) // 231
19-02-2023
Given a string array, find the maximum product of word lengths where the words don’t share any letters.
(Given the example and how late I was to send this, I assumed we were looking only for the bigger product between two words)
// Example:
// > wordLengthProduct(["fish","fear","boo","egg","cake","abcdef"])
// > 16 // "fish" and "cake"
// > wordLengthProduct(["a","aa","aaa","aaaa"])
// > 0 // all of them share "a"
function wordLengthProduct(words) {
let product = 0
words.forEach((wordA) => {
words.forEach((wordB) => {
if (wordA === wordB) {
return
}
if (!shareSomeLetter(wordA, wordB)) {
const potentialProduct = wordA.length * wordB.length
if (potentialProduct > product) {
product = potentialProduct
}
}
})
})
return product
}
function shareSomeLetter(a, b) {
if (b.length > a.length) {
return shareSomeLetter(b, a)
}
for (let i = 0; i < a.length; i++) {
if (b.includes(a[i])) {
return true
}
}
return false
}
console.log(wordLengthProduct(["fish","fear","boo","egg","cake","abcdef"])) // 16
console.log(wordLengthProduct(["a","aa","aaa","aaaa"])) // 0
12-02-2023
Write a function that produces a generator that produces values in a range.
package main
import "fmt"
import "errors"
func main() {
generator := fromTo(0, 3)
fmt.Println(generator()) // 0 <nil>
fmt.Println(generator()) // 1 <nil>
fmt.Println(generator()) // 2 <nil>
fmt.Println(generator()) // -1 Generator expired
}
func fromTo(from int, to int) func() (int, error) {
current := from
return func() (int, error) {
if current < to {
current++
return current - 1, nil
}
return -1, errors.New("Generator expired")
}
}
29-01-2024
Write a function called daysBetween that takes in two dates, and returns the number of days between those dates
function daysBetween(d1, d2) {
d1ms = new Date(d1).getTime()
d2ms = new Date(d2).getTime()
return Math.abs(Math.round((d1ms-d2ms)/(1000*60*60*24)));
}
console.log(daysBetween('Jan 1, 2024', 'Jan 29, 2024')) // 28
console.log(daysBetween('Feb 29, 2020', 'Oct 31, 2023')) // 1340
22-01-2024
Write a data structure for a simple binary tree, and a function that prints a given tree.
This one took a bit more time, it works, but is not as simple as I’d have hoped.
package main
import "fmt"
import "math"
import "strings"
type Node struct {
Name string
Left *Node
Right *Node
}
func main() {
root := Node{Name: "1"}
root.Left = &Node{Name: "2"}
root.Right = &Node{Name: "3"}
root.Left.Left = &Node{Name: "4"}
root.Left.Right = &Node{Name: "5"}
root.Left.Right.Left = &Node{Name: "6"}
root.Left.Right.Right = &Node{Name: "7"}
printTree(root)
}
/* Output:
1
/ \
2 3
/ \
4 5
/ \
6 7
*/
func getSize(root Node) int {
if root.Left == nil && root.Right == nil {
return 1;
}
if root.Left == nil {
return 1 + getSize(*root.Right)
}
if root.Right == nil {
return 1 + getSize(*root.Left)
}
return 1 + int(math.Max(float64(getSize(*root.Left)), float64(getSize(*root.Right))))
}
func printTree(root Node) {
size := getSize(root)
explo := []*Node{&root}
for i := 1; i <= size; i++{
links := ""
nodeNames := ""
next := make([]*Node, 0)
for k, node := range explo {
nodeSize := int(math.Pow(2, float64(size - i)) * 3)
if node == nil {
nodeNames += strings.Repeat(" ", int(math.Floor(float64(nodeSize))) + 1)
links += strings.Repeat(" ", int(math.Floor(float64(nodeSize))) + 1)
next = append(next, nil, nil)
continue
}
nodeNames += strings.Repeat(" ", int(math.Floor(float64(nodeSize / 2))))
links += strings.Repeat(" ", int(math.Floor(float64(nodeSize / 2))))
if k % 2 == 0 {
links += "/"
} else {
links += "\\"
}
nodeNames += node.Name
nodeNames += strings.Repeat(" ", int(math.Ceil(float64(nodeSize / 2))))
links += strings.Repeat(" ", int(math.Ceil(float64(nodeSize / 2))))
next = append(next, node.Left, node.Right)
}
if i != 1 {
fmt.Println(links)
}
fmt.Println(nodeNames)
explo = next
}
}
15-01-2024
Given a 2D array, write a function that flips it vertically or horizontally.
First time seeing these questions, wrote this simple working solution !
const array = [
[1,2,3],
[4,5,6],
[7,8,9]
]
function flip (flipper, direction) {
if (direction === 'vertical') {
return flipper.toReversed()
}
return flipper.map(row => row.toReversed())
}
console.log(flip(array, 'horizontal'))
//[[3,2,1],[6,5,4],[9,8,7]]
console.log(flip(array, 'vertical'))
//[[7,8,9],[4,5,6],[1,2,3]]
```../components/CassidoosInterviewQuestions/DuplicateNumbers.jsx