Skip to content

Instantly share code, notes, and snippets.

@AndrewSavetchuk
Last active March 17, 2024 23:02
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save AndrewSavetchuk/85a6d3a18161cfdfd93fe2052d0ce171 to your computer and use it in GitHub Desktop.
Save AndrewSavetchuk/85a6d3a18161cfdfd93fe2052d0ce171 to your computer and use it in GitHub Desktop.

Looping a Triangle

Write a loop that makes seven calls to console.log to output the following triangle:

#
##
###
####
#####
######
#######

Solution 1

let output = "";

for (let i = 1; i <= 7; i++) {
  for (let j = 1; j <= i; j++) {
    output += "#";
  }
  
  output += "\n";
}

console.log(output);

Solution 2

let output = "";

for (let i = 1; i <= 7; i++) {
  output += "#";
  console.log(output);
}

Solution 3

function loop(n) {
  let output = "";

  for (let i = 1; i <= n; i++) {
    for (let j = 1; j <= i; j++) {
      output+="#";
    }

    output+="\n";
  }
  
  return output;
}

console.log(loop(10));

FizzBuzz

Write a program that uses console.log to print all the numbers from 1 to 100, with two exceptions.

For numbers divisible by 3, print "Fizz" instead of the number, and for numbers divisible by 5 (and not 3), print "Buzz" instead.

When you have that working, modify your program to print "FizzBuzz" for numbers that are divisible by both 3 and 5 (and still print "Fizz" or "Buzz" for numbers divisible by only one of those).

Solution 1

for (let i = 1; i <= 100; i++) {
  if (i % 3 === 0 && i % 5 === 0) console.log("FizzBuzz");
  else if (i % 3 === 0) console.log("Fizz");
  else if (i % 5 === 0) console.log("Buzz");
  else console.log(i);
}

Solution 2

for (let i = 1; i <= 100; i++) {
  let output = "";
  if (i % 3 === 0) output += "Fizz";
  if (i % 5 === 0) output += "Buzz";
  console.log(output || i);
}

Chessboard

Write a program that creates a string that represents an 8x8 grid, using newline characters to separate lines. At each position of the grid there is either a space or a # character. The characters should form a chessboard.

Example:

 # # # #
# # # #
 # # # #
# # # #
 # # # #
# # # #
 # # # #
# # # #

When you have a program that generates this pattern, define a binding size = 8 and change the program so that it works for any size, outputting a grid of the given width and height.

Solution

function chessboard(size) {
  let output = "";

  for (let i = 0; i <= size; i++) {
    for (let j = 0; j <= size; j++) {
      output += (i + j) % 2 === 0 ? " " : "#";
    }
    
    output += "\n";
  }
  
  return output;
}

console.log(chessboard(8));

Find Minimum Number

Write a function similar to Math.min that takes two arguments and returns their minimum.

Solution

function min(a, b) {
  return a < b ? a : b;
}

console.log(min(5, 3));

Now modify the function so that it can accept any number of arguments.

function min(...args) {
  let min = args[0];
  
  for (let i = 1; i < args.length; i++) {
    if (args[i] < min) {
      min = args[i];
    }
  }
  
  return min;
}

console.log(min(5, 3, 8, 1));

Even or Odd

The remainder operator (%) can be used to test whether a number is even or odd by using % 2 to see whether it's divisible by two. Here's another way to define whether a positive whole number is even or odd:

  • Zero is even.
  • One is odd.
  • For any other number N, its evenness is the same as N - 2.

Define a recursive function isEven corresponding to this description. The function should accept a single parameter (a positive, whole number) and return a Boolean.

Test it on 50 and 75. See how it behaves on -1. Why? Can you think of a way to fix this?

Solution

function isEven(n) {
  if (n === 0) {
    return true;
  } else if (n === 1) {
    return false;
  } else if (n < 0) {
    return isEven(-n);
  } else {
    return isEven(n - 2);
  }
}

console.log(isEven(-1));

Note: as an alternative solution, it is possible to fix the problem with negative numbers using Math.abs(n).

Generator Take

Using generator, write a function that will take the first N items from an array and print it in the console.

For example: console.log(...take(3, ['a', 'b', 'c', 'd', 'e'])); // => a b c

Solution

function * take(n, array) {
  for (let i = 0; i < n; i++) {
    yield array[i];
  }
}

console.log(...take(3, ['a', 'b', 'c', 'd', 'e']));

Remove Duplicates From Array

Remove duplicates from array based on the key from an array of objects.

You should return a new array without changing the input array.

Input:
[
  {key: 1, value: 'a'},
  {key: 2, value: 'b'},
  {key: 4, value: 'c'},
  {key: 5, value: 'd'},
  {key: 4, value: 'e'},
  {key: 2, value: 'f'},
  {key: 6, value: 'g'}
]

Output:
[
  { key: 1, value: 'a' },
  { key: 2, value: 'b' },
  { key: 4, value: 'c' },
  { key: 5, value: 'd' },
  { key: 6, value: 'g' }
]

Solution 1

const arr = [
  {key: 1, value: 'a'},
  {key: 2, value: 'b'},
  {key: 4, value: 'c'},
  {key: 5, value: 'd'},
  {key: 4, value: 'e'},
  {key: 2, value: 'f'},
  {key: 6, value: 'g'},
];

function removeDuplicates(array) {
  const tempKeys = [];
  const newArray = [];
  
  for (let i = 0; i < array.length; i++) {
    if (tempKeys[array[i].key]) {
      continue;
    }
    
    tempKeys[array[i].key] = true;
    newArray.push(array[i]);
  }
  
  return newArray;
}

console.log(removeDuplicates(arr));

Solution 2

const arr = [
  {key: 1, value: 'a'},
  {key: 2, value: 'b'},
  {key: 4, value: 'c'},
  {key: 5, value: 'd'},
  {key: 4, value: 'e'},
  {key: 2, value: 'f'},
  {key: 6, value: 'g'},
];

function removeDuplicates(array) {
  const keys = array.map((item) => item.key);
  
  return array.filter((item, index) => keys.indexOf(item.key) === index);
}

console.log(removeDuplicates(arr));

Find Solution

Consider this puzzle: by starting from the number 1 and repeatedly either adding 5 or multiplying by 3, an infinite set of numbers can be produced.

Write a function that, given a number, tries to find a sequence of such additions and multiplications that produces that number. For example, the number 13 could be reached by first multiplying by 3 and then adding 5 twice, whereas the number 15 cannot be reached at all.

Example:

console.log(findSolution(13)); // => (((1 * 3) + 5) + 5)

Solution

function findSolution(targetNumber) {
  function find(number, history) {
    if (number === targetNumber) {
      return history;
    } else if (number > targetNumber) {
      return null;
    } else {
      return find(number + 5, `(${history} + 5)`) ||
        find(number * 3, `(${history} * 3)`);
    }
  }

  return find(1, '1');
}

console.log(findSolution(13));

Count Bs

You can get the Nth character, or letter, from a string by writing "string"[N]. The first character has position 0, which causes the last one to be found at position string.length - 1.

Write a function countBs that takes a string as its only argument and returns a number that indicates how many uppercase "B" characters there are in the string.

Next, write a function called countChar that behaves like countBs, except it takes a second argument that indicates the character that is to be counted (rather than counting only uppercase "B" characters).

Finally, rewrite countBs to make use of this new function.

Example:

console.log(countBs('The quick Brown fox jumps over a lazy dog.')); // => 1

Solution

function countBs(str) {
  return countChar(str, 'B');
}

function countChar(str, targetChar) {
  let count = 0;
  
  for (let i = 0; i < str.length; i++) {
    if (str[i] === targetChar) {
      count++;
    }
  }
  
  return count;
}

console.log(countBs('The quick Brown fox jumps over a lazy dog.'));

Remove and Concat

Write a function that takes an array and an index, and it returns a new array that is a copy of the original array with the element at the given index removed.

Example:

console.log(remove(['a', 'b', 'c', 'd', 'e'], 2)); // => ['a', 'b', 'd', 'e']

Solution

function remove(arr, index) {
  return arr.slice(0, index).concat(arr.slice(index + 1));
}

console.log(remove(['a', 'b', 'c', 'd', 'e'], 2));

Sum of a Range

Write a range function that takes two arguments, start and end, and returns an array containing all the numbers from start up to (and including) end.

Next, write a sum function that takes an array of numbers and returns the sum of these numbers.

Run the example program and see whether it does indeed return 55.

console.log(sum(range(1, 10))); // => 55

As a bonus assignment, modify your range function to take an optional third argument that indicates the "step" value used when building the array. If no step is given, the elements go up by increments of one, corresponding to the old behavior.

The function call range(1, 10, 2) should return [1, 3, 5, 7, 9].

Make sure it also works with negative step values so that range(5, 2, -1) produces [5, 4, 3, 2].

console.log(range(1, 10, 2)); // => [1, 3, 5, 7, 9]

console.log(range(5, 2, -1)); // => [5, 4, 3, 2]

Solution

function range(start, end, step = start < end ? 1 : -1) {
  const result = [];

  if (step > 0) {
    for (let i = start; i <= end; i += step) {
      result.push(i);
    }
  } else {
    for (let i = start; i >= end; i += step) {
      result.push(i);
    }
  }
  
  return result;
}

function sum(range) {
  let result = 0;
  
  for (let i = 0; i < range.length; i++) {
    result += range[i];
  }
  
  return result;
}

console.log(sum(range(1, 10)));

console.log(range(5, 2, -1));

Reversing an Array

Arrays have a reverse method that changes the array by inverting the order in which its elements appear. For this exercise, write two function, reverseArray and reverseArrayInPlace.

The first, reverseArray, takes an array as argument and produces a new array that has the same elements in the inverse order. The second, reverseArrayInPlace, does what the reserve method does: it modifies the array given as argument by reversing its elements. Neither function may use the standard reverse method.

Example:

const arr = [1, 2, 3];

console.log(reverseArray(arr)); // => [3, 2, 1]
console.log(arr); // => [1, 2, 3]

console.log(reverseArrayInPlace(arr)); // => [3, 2, 1]
console.log(arr); // => [3, 2, 1]

Solution

function reverseArray(arr) {
  const result = [];
  
  // As an alternative, we can use a regular loop with array.unshift()
  for (let i = arr.length - 1; i >= 0; i--) {
    result.push(arr[i]);
  }
  
  return result;
}

function reverseArrayInPlace(arr) {
  for (let i = 0; i < Math.floor(arr.length / 2); i++) {
    const temp = arr[i];
    arr[i] = arr[arr.length - i - 1];
    arr[arr.length - i - 1] = temp;
  }
  
  return arr;
}

const arr = [1, 2, 3];

console.log(reverseArray(arr));
console.log(arr);

console.log(reverseArrayInPlace(arr));
console.log(arr);

List to Array and Array to List

Objects, as generic blobs of values, can be used to build all sorts of data structures.

A common data structure is the list (not to be confused with the array). A list is a nested set of objects, with the first object holding a reference to the second, the second to the third, and so on.

const list = {
  value: 1,
  rest: {
    value: 2,
    rest: {
      value: 3,
      rest: null
    }
  }
};

A nice thing about lists is that they can share parts of their structure. For example, if we create two new values { value: 0, rest: list } and { value: 1, rest: list } (with list referring to the binding defined earlier), they are both independent lists, but they share the structure that makes up their last three elements. The original list is also still a valid three-element list.

Write a function arrayToList that builds up a list structure like the one shown when given [1, 2, 3] as argument.

Also write a listToArray function that produces an array from a list.

Then add a helper function prepend, which takes an element and a list and creates a new list that adds the element to the front of the input list, and nth, which takes a list and a number and returns the element at the given position in the list (with zero referring to the first element) or undefined when there is no such element. If you haven't already, also write a recursive version of nth.

Example:

console.log(arrayToList([10, 20])); 
// → {value: 10, rest: {value: 20, rest: null}}

console.log(listToArray(arrayToList([10, 20, 30]))); 
// → [10, 20, 30]

console.log(prepend(10, prepend(20, null))); 
// → {value: 10, rest: {value: 20, rest: null}}

console.log(nth(arrayToList([10, 20, 30]), 1)); 
// → 20

Solution 1

function arrayToList(arr) {
  if (arr.length === 0) {
    return null;
  }

  return {
    value: arr[0],
    rest: arrayToList(arr.slice(1)),
  };
}

function listToArray(list) {
  if (! list) {
    return [];
  }
  
  return [list.value].concat(listToArray(list.rest));
}

console.log(arrayToList([10, 20])); 
// → {value: 10, rest: {value: 20, rest: null}}

console.log(listToArray(arrayToList([10, 20, 30]))); 
// → [10, 20, 30]

Solution 2

function arrayToList(arr) {
  let list = null;
  
  for (let i = arr.length- 1; i >= 0; i--) {
    list = prepend(arr[i], list);
  }
  
  return list;
}

function listToArray(list) {
  const array = [];
  
  for (let node = list; node; node = node.rest) {
    array.push(node.value);
  }
  
  return array;
}

function prepend(value, list) {
  return {
    value,
    rest: list,
  };
}

function nth(list, position) {
  if (! list) {
    return undefined;
  }
  
  if (position === 0) {
    return list.value;
  }
  
  return nth(list.rest, position - 1);
}

console.log(arrayToList([10, 20]));
// → {value: 10, rest: {value: 20, rest: null}}

console.log(listToArray(arrayToList([10, 20, 30])));
// → [10, 20, 30]

console.log(prepend(10, prepend(20, null)));
// → {value: 10, rest: {value: 20, rest: null}}

console.log(nth(arrayToList([10, 20, 30]), 1));
// → 20

Deep Comparison

The == operator compares objects by identity. But sometimes you'd prefer to compare the values of their actual properties.

Write a function deepEqual that takes two values and returns true only if they are the same value or are objects with the same properties, where the values of the properties are equal when compared with a recursive call to deepEqual.

To find out whether values should be compared directly (use the === operator for that) or have their properties compared, you can use the typeof operator. If it produces "object" for both values, you should do a deep comparison. But you have to take one silly exception into account: because of a historical incident, typeof null also produces "object".

The Object.keys function will be useful when you need to go over the properties of objects to compare them.

Example:

let obj = { here: { is: "an" }, object: 2 };

console.log(deepEqual(obj, obj));
// → true

console.log(deepEqual(obj, { here: 1, object: 2 }));
// → false

console.log(deepEqual(obj, { here: { is: "an" }, object: 2 }));
// → true

console.log(deepEqual(5, 5));
// → true

console.log(deepEqual(obj, null));
// → false

Solution

function deepEqual(a, b) {
  if (a === b) {
    return true;
  }
  
  if (a === null || typeof a !== 'object' || b === null || typeof b !== 'object') {
    return false;
  }
  
  const keysA = Object.keys(a);
  const keysB = Object.keys(b);
  
  if (keysA.length !== keysB.length) {
    return false;
  }
  
  for (let key of keysA) {
    if (!keysB.includes(key) || !deepEqual(a[key], b[key])) {
      return false;
    }
  }
  
  return true;
}

let obj = { here: { is: "an" }, object: 2 };

console.log(deepEqual(obj, obj));
// → true

console.log(deepEqual(obj, { here: 1, object: 2 }));
// → false

console.log(deepEqual(obj, { here: { is: "an" }, object: 2 }));
// → true

console.log(deepEqual(5, 5));
// → true

console.log(deepEqual(obj, null));
// → false

Largest Number At Least Twice of Others

You are given an integer array nums where the largest integer is unique.

Determine whether the largest element in the array is at least twice as much as every other number in the array.

If it is, return the index of the largest element, or return -1 otherwise.

Example 1

Input: nums = [3,6,1,0]
Output: 1

For every other number in the array x, 6 is at least twice as big as x. The index of value 6 is 1, so we return 1.

Example 2

Input: nums = [1,2,3,4]
Output: -1

4 is less than twice the value of 3, so we return -1.

Constraints

2 <= nums.length <= 50
0 <= nums[i] <= 100
The largest element in nums is unique.

Solution 1

/**
 * @param {number[]} nums
 * @return {number}
 */
var dominantIndex = function(nums) {
  let largestIndex = 0;
  
  for (let i = 1; i <= nums.length; i++) {
    if (nums[i] > nums[largestIndex]) {
      largestIndex = i;
    }
  }
  
  for (let i = 0; i < nums.length; i++) {
    if (i !== largestIndex && nums[largestIndex] < 2 * nums[i]) {
      return -1;
    }
  }
  
  return largestIndex;
};

Solution 2

/**
 * @param {number[]} nums
 * @return {number}
 */
const dominantIndex = function(nums) {
  let largestIndex = 0;
  let secondLargestIndex = 1;
  
  for (let i = 1; i <= nums.length; i++) {
    if (nums[i] > nums[largestIndex]) {
      secondLargestIndex = largestIndex;
      largestIndex = i;
    }
    
    else if (nums[i] > nums[secondLargestIndex]) {
      secondLargestIndex = i;
    }
  }
  
  if (nums[largestIndex] - nums[secondLargestIndex] >= nums[secondLargestIndex]) {
    return largestIndex;
  }
  
  return -1;
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment