• Largest Subarray Length K

    /**
     * @param {number[]} nums
     * @param {number} k
     * @return {number[]}
     */
    var largestSubarray = function(arr, k) {
      let max = arr[0];
      let maxIndex = 0;
      for (let i = 0; i <= arr.length - k; i++) {
        if (arr[i] > max) {
          max = arr[i];
          maxIndex = i;
        }
      }
    
      return arr.slice(maxIndex, maxIndex + k);
    };
    
    console.log(largestSubarray([1, 4, 5, 2, 3], 4));
    // [4, 5, 2, 3]
    

    Demo

  • Heap

    Max Heap (Javascript)

    class MaxHeap {
      constructor(capacity) {
        this.capacity = capacity;
        this.size = 0;
        this.arr = [];
      }
    
      add(val) {
        if (this.size < this.capacity) {
          this.arr[this.size++] = val;
          this.trickleUp(this.size - 1);
        }
      }
    
      trickleUp(i) {
        const parent = Math.floor((i - 1) / 2);
        if (parent >= 0 && this.arr[i] > this.arr[parent]) {
          this.swap(i, parent);
          this.trickleUp(parent);
        }
      }
    
      delete() {
        if (this.size) {
          const ret = this.arr[0];
          this.arr[0] = this.arr[this.size-- - 1];
          this.trickleDown(0);
          return ret;
        }
      }
    
      trickleDown(i) {
        const left = 2 * i + 1;
        const right = 2 * i + 2;
        let largest = i;
        if (left < this.size && this.arr[left] > this.arr[largest]) {
          largest = left;
        }
        if (right < this.size && this.arr[right] > this.arr[largest]) {
          largest = right;
        }
        if (largest !== i) {
          this.swap(i, largest);
          this.trickleDown(largest);
        }
      }
    
      swap(a, b) {
        const temp = this.arr[a];
        this.arr[a] = this.arr[b];
        this.arr[b] = temp;
      }
    
      hasNext() {
        return this.size > 0;
      }
    }
    
    /** Test **/
    const maxHeap = new MaxHeap(1000);
    maxHeap.add(1);
    maxHeap.add(90);
    maxHeap.add(11);
    maxHeap.add(5);
    while (maxHeap.hasNext()) {
      console.log(maxHeap.delete());
    }
    
    /* 
     Output:
         		90
         		11
         		5
         		1
    */
    
    // Time complexity for each operation: O(log(n)).
    

    Demo

  • Design Add and Search Words Data Structure

    The following code uses “Trie” data structure. The character ‘.’ in a word could represent any letter when searching.

    class TrieNode {
      constructor(val) {
        this.val = val;
        this.children = {};
        this.isWord = false;
      }
    }
    
    var WordDictionary = function() {
      this.root = new TrieNode(null);
    };
    
    /** 
     * @param {string} word
     * @return {void}
     */
    WordDictionary.prototype.addWord = function(word) {
      let current = this.root;
      const charArray = word.split('');
      for (const s of charArray) {
        if (!(s in current.children)) {
          current.children[s] = new TrieNode(s);
        }
        current = current.children[s];
      }
      current.isWord = true;
    };
    
    /** 
     * @param {string} word
     * @return {boolean}
     */
    WordDictionary.prototype.search = function(word) {
      return this.searchString(word, this.root);
    };
    
    WordDictionary.prototype.searchString = function(str, node) {
      let current = node;
      const charArray = str.split('');
      for (const [index, char] of Object.entries(charArray)) {
        if (!(char in current.children)) {
          if (char === '.') {
            for (const [key, childNode] of Object.entries(current.children)) {
              if (this.searchString(str.substring(parseInt(index) + 1), childNode)) {
                return true;
              }
            }
          }
          return false;
        } else {
          current = current.children[char];
        }
      }
      return current.isWord;
    };
    
    var obj = new WordDictionary();
    obj.addWord('bad');
    obj.addWord('bat');
    obj.addWord('cat');
    console.log(obj.search('b..')); // true
    console.log(obj.search('cat')); // true
    console.log(obj.search('dog')); // false
    

    Demo

  • Coin Change

    /**
     * @param {number[]} coins
     * @param {number} amount
     * @return {number}
     */
    const coinChange = (coins, amount) => {
      if (!coins) {
        return -1;
      }
      return getCoinChangeMin(coins, amount, {});
    };
    
    const getCoinChangeMin = (coins, amount, dp) => {
      if (amount < 0) {
        return -1;
      }
      if (amount === 0) {
        return 0;
      }
      if (amount in dp) {
        return dp[amount];
      }
      let min = Number.MAX_VALUE;
      for (const coin of coins) {
        let currMin = getCoinChangeMin(coins, amount - coin, dp);
        if (currMin >= 0 && currMin < min) {
          min = currMin;
        }
      }
      return dp[amount] = min === Number.MAX_VALUE ? -1 : min + 1;
    };
    
    
  • N-Queens Js

    const solveNQueens = (n) => {
      if (n < 1) {
        return [];
      }
      const ret = [];
      getAll(n, 0, ret, []);
      return ret;
    };
    
    
    const getAll = (n, row, ret, rowCol) => {
      if (row === n) {
        ret.push(buildSolution(rowCol, n));
        return;
      }
    
      for (let col = 0; col < n; col++) {
        if (isValid(row, col, rowCol)) {
          rowCol[row] = col;
          getAll(n, row + 1, ret, rowCol);
        }
      }
    };
    
    const isValid = (row, col, rowCol) => {
      for (let r = 0; r < row; r++) {
        if (rowCol[r] === col) {
          return false;
        }
    
        const c = rowCol[r];
    
        if ((row - r) === Math.abs(c - col)) {
          return false;
        }
      }
      return true;
    };
    
    const buildSolution = (rowCol, n) => {
      const ans = [];
      for (let i = 0; i < n; i++) {
        let str = '';
        for (let j = 0; j < n; j++) {
          str += rowCol[i] === j ? 'Q' : '.';
        }
        ans.push(str);
      }
      return ans;
    };
    
  • 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

  • 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);
        }
      }
    };
  • 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);
    };
  • 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

  • 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.