Categories
interview

Container With Most Water

/**
 * @param {number[]} height
 * @return {number}
 */
const maxArea = (height) => {
  let low = 0;
  let high = height.length - 1;
  let max = 0;
  while (low < high) {
    max = Math.max(max, (high - low) * Math.min(height[low], height[high]));
    if (height[low] <= height[high]) {
      low++
    } else {
      high--;
    }
  }
  return max;
};

console.log(maxArea([1, 8, 6, 2, 5, 4, 8, 3, 7])); // 49

Demo

Categories
interview

Group Anagrams

Group Permutations of the same strings in a given list in Javascript:

/**
 * @param {string[]} strs
 * @return {string[][]}
 */
const groupAnagrams = function(strs) {
  const obj = {};
  for (const str of strs) {
    const key = str.split('').sort().join('');
    (obj[key] || (obj[key] = [])).push(str);
  }
  return Object.values(obj);
};

console.log(groupAnagrams(['abc', 'bbc', 'cab', 'ccc']));
// [["abc", "cab"], ["bbc"], ["ccc"]]

Demo

Categories
interview

Rotate Image

Javascript (ES6) code to rotate a Image or a 2D square matrix in place:

const rotate = (matrix) => {
  const n = matrix.length;
  for (let layer = 0; layer < Math.floor(n / 2); layer++) {
    for (let i = layer; i < n - layer - 1; i++) {
      const temp = matrix[layer][i];
      matrix[layer][i] = matrix[n - i - 1][layer];
      matrix[n - i - 1][layer] = matrix[n - layer - 1][n - i - 1];
      matrix[n - layer - 1][n - i - 1] = matrix[i][n - layer - 1];
      matrix[i][n - layer - 1] = temp;
    }
  }
};

Demo

Output


rotate([
  [1, 2, 3],
  [4, 5, 6],
  [7, 8, 9],
]);

/*
[
  [7, 4, 1],
  [8, 5, 2],
  [9, 6, 3],
]
*/
Categories
interview

Event Emitter pattern

Event emitter pattern implemented using a Javascript ES6 class.

class EventEmitter {
  events = {};

  subscribe = (event, cb) => {
    (this.events[event] || (this.events[event] = [])).push(cb);
    return {
      unsubscribe: () => {
        const arr = this.events[event];
        (arr.length && arr.splice(arr.indexOf(cb) >>> 0, 1);
      }
    };
  };

  emit = (event, ...rest) => {
    (this.events[event] || []).forEach(val => {
      val(...rest);
    });
  };
}

const eventEmitter = new EventEmitter();
const ret1 = eventEmitter.subscribe('test', () => {
  console.log('test1');
});
const ret2 = eventEmitter.subscribe('test', () => {
  console.log('test2');
});
const ret3 = eventEmitter.subscribe('test3', () => {
  console.log('test3');
});
eventEmitter.emit('test'); // test1, test2
ret1.unsubscribe();
ret1.unsubscribe(); // Should still function as expected.
eventEmitter.emit('test'); // test2

Demo

Categories
interview

Employee badging times – Javascript

We are working on a security system for a badged-access room in our company’s building.

We want to find employees who badged into our secured room unusually often. We have an unordered list of names and entry times over a single day. Access times are given as numbers up to four digits in length using 24-hour time, such as “800” or “2250”.

Write a function that finds anyone who badged into the room three or more times in a one-hour period. Your function should return each of the employees who fit that criteria, plus the times that they badged in during the one-hour period. If there are multiple one-hour periods where this was true for an employee, just return the earliest one for that employee.

badge_times = [
[‘Paul’, ‘1355’],
[‘Jennifer’, ‘1910’],
[‘Jose’, ‘835’],
[‘Jose’, ‘830’],
[‘Paul’, ‘1315’],
[‘Chloe’, ‘0’],
[‘Chloe’, ‘1910’],
[‘Jose’, ‘1615’],
[‘Jose’, ‘1640’],
[‘Paul’, ‘1405’],
[‘Jose’, ‘855’],
[‘Jose’, ‘930’],
[‘Jose’, ‘915’],
[‘Jose’, ‘730’],
[‘Jose’, ‘940’],
[‘Jennifer’, ‘1335’],
[‘Jennifer’, ‘730’],
[‘Jose’, ‘1630’],
[‘Jennifer’, ‘5’],
[‘Chloe’, ‘1909’],
[‘Zhang’, ‘1’],
[‘Zhang’, ’10’],
[‘Zhang’, ‘109’],
[‘Zhang’, ‘110’],
[‘Amos’, ‘1’],
[‘Amos’, ‘2’],
[‘Amos’, ‘400’],
[‘Amos’, ‘500’],
[‘Amos’, ‘503’],
[‘Amos’, ‘504’],
[‘Amos’, ‘601’],
[‘Amos’, ‘602’],
[‘Paul’, ‘1416’],
];

Expected output (in any order)

{
Paul: [‘1315’, ‘1355’, ‘1405’],
Jose: [‘830’, ‘835’, ‘855’, ‘915’, ‘930’],
Zhang: [’10’, ‘109’, ‘110’],
Amos: [‘500’, ‘503’, ‘504’],
}
n: length of the badge records array.

const badge_records = [
  ['Paul', '1355'],
  ['Jennifer', '1910'],
  ['Jose', '835'],
  ['Jose', '830'],
  ['Paul', '1315'],
  ['Chloe', '0'],
  ['Chloe', '1910'],
  ['Jose', '1615'],
  ['Jose', '1640'],
  ['Paul', '1405'],
  ['Jose', '855'],
  ['Jose', '930'],
  ['Jose', '915'],
  ['Jose', '730'],
  ['Jose', '940'],
  ['Jennifer', '1335'],
  ['Jennifer', '730'],
  ['Jose', '1630'],
  ['Jennifer', '5'],
  ['Chloe', '1909'],
  ['Zhang', '1'],
  ['Zhang', '10'],
  ['Zhang', '109'],
  ['Zhang', '110'],
  ['Amos', '1'],
  ['Amos', '2'],
  ['Amos', '400'],
  ['Amos', '500'],
  ['Amos', '503'],
  ['Amos', '504'],
  ['Amos', '601'],
  ['Amos', '602'],
  ['Paul', '1416']
];

const getOftenUsersOfBadge = (records) => {
  records.sort((a, b) => a[1] - b[1]);
  const obj = {};
  for (const [name, time] of records) {
    (obj[name] || (obj[name] = [])).push(time);
  }
  const result = {};
  for (const [key, val] of Object.entries(obj)) {
    const len = val.length;
    if (len >= 3) {
      for (let i = 2; i < len; i++) {
        if (val[i] - val[i - 2] <= 100) {
          const start = i - 2;
          const max = parseInt(val[start]) + 100;
          while (parseInt(val[++i]) <= max) {}
          result[key] = val.slice(start, i);
          break;
        }
      }
    }
  }
  return result;
};

console.log(getOftenUsersOfBadge(badge_records));

/* Explanation:
1) Sort the input records based on times in increasing order.
2) Build a map { name : [time1, time2,  ... timen], }
3) Computing times
          1 --> 00:01
        101 --> 01:01
        diff is 100 for 1 hour.
    No need to check (i < len) in the while loop as we break the loop on first failure of condition.
*/

Demo

Categories
interview

2D Array JavaScript (ES6)

const twoDarray = Array(3).fill(0).map(x => Array(3).fill(0));

console.log(twoDarray);
// [[0, 0, 0], [0, 0, 0], [0, 0, 0]]

Demo

Categories
interview

Find mismatches in badging records

Given an ordered list of employees who used their badge to enter or exit the room, write a function that returns two collections:
1. All employees who didn’t use their badge while exiting the room – they recorded an enter without a matching exit. (All employees are required to leave the room before the log ends.)
2. All employees who didn’t use their badge while entering the room – they recorded an exit without a matching enter. (The room is empty when the log begins.)
Each collection should contain no duplicates, regardless of how many times a given employee matches the criteria for belonging to it.

records1 = [
	  ["Martha",   "exit"],
	  ["Paul",     "enter"],
	  ["Martha",   "enter"],
	  ["Steve",    "enter"],
	  ["Martha",   "exit"],
	  ["Jennifer", "enter"],
	  ["Paul",     "enter"],
	  ["Curtis",   "exit"],
	  ["Curtis",   "enter"],
	  ["Paul",     "exit"],
	  ["Martha",   "enter"],
	  ["Martha",   "exit"],
	  ["Jennifer", "exit"],
	  ["Paul",     "enter"],
	  ["Paul",     "enter"],
	  ["Martha",   "exit"],
	  ["Paul",     "enter"],
	  ["Paul",     "enter"],
	  ["Paul",     "exit"],
	  ["Paul",     "exit"] 
	]

Expected output: ["Paul", "Curtis", "Steve"], ["Martha", "Curtis", "Paul"]

Other test cases:

records2 = [
	  ["Paul", "enter"],
	  ["Paul", "exit"],
	]

Expected output: [], []

records3 = [
	  ["Paul", "enter"],
	  ["Paul", "enter"],
	  ["Paul", "exit"],
	  ["Paul", "exit"],
	]

Expected output: ["Paul"], ["Paul"]

records4 = [
	  ["Paul", "enter"],
	  ["Paul", "exit"],
	  ["Paul", "exit"],
	  ["Paul", "enter"],
	]

Expected output: ["Paul"], ["Paul"]
const mismatches = (records) => {
  const obj = {};
  const notExited = [];
  const notEntered = [];
  for (const [name, state] of records) {
    if (!(name in obj)) {
      obj[name] = 0;
    }

    if (state === 'enter') {
      obj[name]++;
    } else {
      obj[name]--;
    }

    if (obj[name] > 1) {
      if (!notExited.includes(name)) {
        notExited.push(name);
      }
      obj[name] = 0;
    }
    if (obj[name] < 0) {
      if (!notEntered.includes(name)) {
        notEntered.push(name);
      }
      obj[name] = 0;
    }
  }

  for (const [key, val] of Object.entries(obj)) {
    if (val === 1) {
      if (!notExited.includes(key)) {
        notExited.push(key);
      }
    }
  }
  return [notExited, notEntered];
};

console.log(mismatches([
    ["Martha", "exit"],
    ["Paul", "enter"],
    ["Martha", "enter"],
    ["Steve", "enter"],
    ["Martha", "exit"],
    ["Jennifer", "enter"],
    ["Paul", "enter"],
    ["Curtis", "exit"],
    ["Curtis", "enter"],
    ["Paul", "exit"],
    ["Martha", "enter"],
    ["Martha", "exit"],
    ["Jennifer", "exit"],
    ["Paul", "enter"],
    ["Paul", "enter"],
    ["Martha", "exit"],
    ["Paul", "enter"],
    ["Paul", "enter"],
    ["Paul", "exit"],
    ["Paul", "exit"]
  ]),
  mismatches([
    ["Paul", "enter"],
    ["Paul", "exit"]
  ]),
  mismatches([
    ["Paul", "enter"],
    ["Paul", "enter"],
    ["Paul", "exit"],
    ["Paul", "exit"],
  ]),
  mismatches([
    ["Paul", "enter"],
    ["Paul", "exit"],
    ["Paul", "exit"],
    ["Paul", "enter"],
  ]));

Demo

Categories
interview

Implement getElementById() polyfill

Implement a method to search for an element in DOM by it’s Id. We use Breadth First Search (BFS) algorithm to traverse the DOM and store the elements in a queue in the following example.
Example: document.getElementById(‘demo’)

<div id="demo">
  <div>1</div>
  <div>2</div>
  <div>
    <div id="hello">Hello world!</div>
  </div>
  <div>3</div>
</div>
<script>
const getElementById = (element, id) => {
  const queue = [element];
  while (queue.length) {
    const curr = queue.shift();
    if (curr.id === id) {
      return curr;
    }
    if (curr.children.length) {
      queue.push(...curr.children);
    }
  }
};

console.log(getElementById(document.documentElement, 'hello').innerHTML); // Hello world!
</script>

Demo

Categories
interview

Valid Parentheses

/**
 * @param {string} str
 * @return {boolean}
 */
const isValid = function(str) {
  /*  
    if (typeof str !== 'string') {
      return false;
    }
  */
  const stack = [];
  const map = {
    ')': '(',
    '}': '{',
    ']': '['
  };

  for (const char of str) {
    if (Object.values(map).includes(char)) {
      stack.push(char);
    } else if (Object.keys(map).includes(char)) {
      if (map[char] !== stack[stack.length - 1]) {
        return false;
      }
      stack.pop();
    }
  }

  return stack.length === 0;
};

console.log(
  isValid('{{[test]})'), // false
  isValid('({[test]})'), // true
  isValid('({['), // false
  isValid(''), // true
);

/* You can verify the following cases as well, by uncommenting the if statement at the start of the method.
console.log(
  isValid(),            // false
  isValid(null),        // false
  isValid(0),           // false
  isValid(1),           // false
  isValid(1.12)         // false
);
*/

Demo

Categories
interview

HTML element as a datastore

The dataset read-only property of the HTMLElement interface provides read/write access to custom data attributes (data-*) on elements. It exposes a map of strings (DOMStringMap) with an entry for each data- attribute.

HTMLElement.dataset

<div id="demo" data-user="john"></div>
<script>
const element = document.getElementById('demo');

// Set a data attribute.
element.dataset.dateOfBirth = '2000-10-10';
// HTML: <div id="demo" data-user="john" data-date-of-birth="2000-10-10"></div>

delete element.dataset.dateOfBirth;
// HTML: <div id="demo" data-user="john"></div>
</script>

Demo