Categories
interview

Implementing a Trie in Javascript

class TrieNode {
  constructor(val) {
    this.val = val;
    this.children = {};
    this.isWord = false;
  }
}

class Trie {
  constructor() {
    this.root = new TrieNode();
  }

  insert(str) {
    let current = this.root;
    for (const char of str) {
      if (!(char in current.children)) {
        current.children[char] = new TrieNode(char);
      }
      current = current.children[char];
    }
    current.isWord = true;
  }

  search(str) {
    let current = this.root;
    for (const char of str) {
      if (!(char in current.children)) {
        return false;
      }
      current = current.children[char];
    }
    return current.isWord;
  }
}

const trie = new Trie();
trie.insert('john');
trie.insert('smith');
console.log(trie.search('john')); // true
console.log(trie.search('smith')); // true
console.log(trie.search('johny')); // false
console.log(trie.search('Tesla')); // false
console.log(trie.search('John')); // false

Demo

Categories
interview

Letter Combinations of a Phone Number

/**
 * @param {string} digits
 * @return {string[]}
 */
var letterCombinations = function(digits) {
  if  (!digits) {
    return [];
  }
const result = [];
const map = {2: 'abc',
3: 'def',
4:'ghi',
5:'jkl',
6:'mno',
7:'pqrs',
8: 'tuv',
9:'wxyz',};
  computeCombinations(map, digits, 0, result, '');
  return result;
};

const computeCombinations = (map, digits, index, result, str) => {
  if (index === digits.length) {
    result.push(str);
  } else {
    for (const letter of map[digits[index]].split('')) {
       computeCombinations(map, digits, index + 1, result, str + letter);
    }
  }
};
Categories
interview

Top K Frequent Words

/**
* @param {string[]} words
* @param {number} k
* @return {string[]}
*/
const topKFrequent = (words, k) => {
  const wordFreq = {};
  for (const word of words) {
    if (word in wordFreq) {
      wordFreq[word]++;
    } else {
      wordFreq[word] = 0;
    }
  }

  return [...new Set(words)].sort((a, b) => {
    if (wordFreq[a] === wordFreq[b]) {
      return a.localeCompare(b);
    } else {
      return wordFreq[b] - wordFreq[a];
    }
  }).slice(0, k);
};
Categories
interview

KMP (Knuth–Morris–Pratt) Algorithm

// Knuth–Morris–Pratt algorithm.
const patternMatch = function(pattern, str) {
  let i = 0;
  let j = 0;
  let n = str.length;
  let m = pattern.length;
  const lps = [];

  // Compute longest prefix string.
  computeLPS(pattern, m, lps);

  while (i < n) {
    if (str.charAt(i) === pattern.charAt(j)) {
      i++;
      j++;
    }
    if (j === m) {
      console.log('String found at: ' + (i - j));
      j = lps[j - 1];
    } else if (i < n && str.charAt(i) !== pattern.charAt(j)) {
      if (j !== 0) {
        j = lps[j - 1];
      } else {
        i++;
      }
    }
  }
};

const computeLPS = function(pattern, m, lps) {
  let i = 1;
  let len = 0;
  while (i < m) {
    if (pattern.charAt(i) === pattern.charAt(len)) {
      lps[i++] = ++len;
    } else {
      if (len > 0) {
        len = lps[len - 1];
      } else {
        lps[i++] = 0;
      }
    }
  }
};

patternMatch('john', 'helloworldjohnhelloworldjohnn');
/*
"String found at: 10"
"String found at: 24"
*/

Demo

Categories
interview

Longest Common Prefix

Find the longest common prefix for a list of strings.

const longestCommonPrefix = (arr) => {
  if (!arr || !arr.length) {
    return;
  }

  let low = 0;
  let high = arr[0].length - 1;

  for (const str of arr) {
    high = Math.min(str.length - 1, high);
  }

  let str = '';

  while (low <= high) {
    const mid = low + Math.floor((high - low) / 2);
    if (hasPrefix(arr, low, mid)) {
      str += arr[0].substring(low, mid + 1);
      low = mid + 1;
    } else {
      high = mid - 1;
    }
  }

  return str;
};

const hasPrefix = (arr, low, mid) => {
  const prefix = arr[0].substring(low, mid + 1);

  for (const str of arr) {
    if (!str.substring(low, mid + 1).startsWith(prefix)) {
      return false;
    }
  }

  return true;
};

console.log(longestCommonPrefix(['johnSmith', 'johnWick', 'john1'])); // 'john'
console.log(longestCommonPrefix(['jo1hnSmith', 'johnWick', 'john1'])); // 'jo'
console.log(longestCommonPrefix(['Smith', 'Wick', 'red'])); // ''

Demo

Runtime complexity: m*log(n)

m = length of the smallest string in the list.

n = length of the list.

Categories
interview

Js reduce() polyfill

Array.prototype.reduce = function(callback, initialValue) {
  let acc = initialValue;
  for (let index = 0; index < this.length; index++) {
    if (!index && acc === undefined) {
      acc = this[index];
    } else {
      acc = callback(acc, this[index], index, this);
    }
  }
  return acc;
};

const arr = [3, 4, 5, 0, -1];
console.log(arr.reduce((acc, curr) => acc + curr)); // 11

Demo

Categories
interview

Array.filter() polyfill

Array.prototype.filter = function(callback, context) {
  const ret = [];
  for (let index = 0; index < this.length; index++) {
    if (callback.call(context, this[index], index, this)) {
      ret.push(this[index]);
    }
  }
  return ret;
};

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

Demo

Categories
interview

Binary search

const binarySearch = (arr, x) => {
  let low = 0;
  let high = arr.length - 1;
  while (low <= high) {
    const mid = low + Math.floor((high - low) /
 2);
    if (x === arr[mid]) {
      return mid;
    } else if (x < arr[mid]) {
      high = mid - 1;
    } else {
      low = mid + 1;
    }
  }
  return -1;
};

const inpArr = [-1, 0, 2, 4, 9, 10, 3000];

console.log(binarySearch(inpArr, 2));  // 2

console.log(binarySearch(inpArr, 11)); // -1

// Runtime Complexity O(log(n))
// Space Complexity O(1)

Demo

Categories
interview

Subsets with no duplicates

Generate subsets with no duplicates.

/**
 * @param {number[]} nums
 * @return {number[][]}
 */
const subsetsWithDup = (nums) => {
  if (!nums) {
    return;
  }

  const len = nums.length;
  const ret = [];
  const subsetStore = {};

  for (let i = 0; i < (1 << len); i++) {
    const currSubset = [];

    for (let j = 0; j < len; j++) {
      if ((1 << j) & i) {
        currSubset.push(nums[j]);
      }
    }

    const subsetKey = [...currSubset].sort((a,b) => a - b).join('.');

    if (!(subsetKey in subsetStore)) {
      ret.push(currSubset);
      subsetStore[subsetKey] = true;
    }

  }

  return ret;
};

console.log(subsetsWithDup([1,1,2]));
// [[], [1], [1, 1], [2], [1, 2], [1, 1, 2]]

Demo

Categories
interview

Looping through Arrays and Objects in Javascript

///  ARRAYS ///
const arr = [1, 2, 3];

for (const val of arr) {
  console.log(val);
}

for (const [key, val] of arr.entries()) {
  console.log(key, val);
}

for (let i = 0; i < arr.length; i++) {
  console.log(arr[i]);
}

///  OBJECTS ///

const obj = {
  abc: 123,
  cc: 33
};

for (const [key, val] of Object.entries(obj)) {
  console.log(key, val);
}

for (const [key] of Object.entries(obj)) {
  console.log(key);
}

for (let key in obj) { // returns Enumerable (peperties whose internal flag is set to true) properties as well.
  if (obj.hasOwnProperty()) {
    console.log(obj[key])
  }
}

Demo