Easy

Solution 1: HashMap

  1. put all numbers x into HashMap<Integer,Boolean> O(n)
  2. traversal array to find if y in the HashMap (y=tragetSum-x) O(n)

Time complexity: O(n)

Space complexity: O(n)

Solution 2: Two pointers

  1. Sort the arrray. O(nLogn)
  2. use Left and Right pointer shrinking the sum to targetSum. O(n)

Time complexity: O(n Log n)  Space complexity: O(1)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
// JavaScript: O(nlog(n)) | O(1) space 
function twoNumberSum(array, targetSum) {
    array.sort((a, b) => a - b);
    let left = 0;
    let right = array.length - 1;
    while (left < right) {
        const currentSum = array[left] + array[right];
        if (currentSum === targetSum) {
            return [array[left], array[right]];
        } else if (currentSum < targetSum) {
            left++;
        } else if (currentSum > targetSum) {
            right--;
        }
    }
    return [];
}

 

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
class Program {
        // O(nlog(n)) | O(1) space
        public static int[] twoNumberSum(int[] array, int targetSum) {
            Arrays.sort(array);
            int left = 0;
            int right = array.length - 1;
            while (left < right) {
                int currentSum = array[left] + array[right];
                if (currentSum == targetSum) {
                    return new int[]{array[left], array[right]};
                } else if (currentSum < targetSum) {
                    left++;
                } else if (currentSum > targetSum) {
                    right--;
                }
            }
            return new int[0];
        }
    }
Given a array arr and a sequence s, check if s is subsequence of arr.

Leetcode Problem

Solution: Two Pointers

  1. Pointer a in array and one pointer b in sequence,
  2. if arr[a]!=sequence[b] a++
  3. else a++ & b++
  4. check if b reach end of length of sequence.

Time complexity: O(n)   n=array length

Space complexity: O(1)

1
2
3
4
5
6
7
8
9
function isValidSubsequence(array, sequence) {
    let arrIdx = 0;
    let seqIdx = 0;
    while (arrIdx < array.length && seqIdx < sequence.length) {
        if (array[arrIdx] === sequence[seqIdx]) seqIdx++;
        arrIdx++;
    }
    return seqIdx === sequence.length;
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
class Program {
        // O(n) time | O(1) space - where n is the length of the array 
        public static boolean isValidSubsequence(List<Integer> array, List<Integer> sequence) {
            int arrIdx = 0;
            int seqIdx = 0;
            while (arrIdx < array.size() && seqIdx < sequence.size()) {
                if (array.get(arrIdx) == sequence.get(seqIdx)) {
                    seqIdx++;
                }
                arrIdx++;
            }
            return seqIdx == sequence.size();
        }
    }

Solution 2: One Pointer in traversal array

1
2
3
4
5
6
7
8
9
  // O(n) time | O(1) space - where n is the length of the array
  function isValidSubsequence(array, sequence) {
      let seqIdx = 0;
      for (const value of array) {
          if (seqIdx === sequence.length) break;
          if (sequence[seqIdx] === value) seqIdx++;
      }
      return seqIdx === sequence.length;
  }

 

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
class Program {
        // O(n) time | O(1) space - where n is the length of the array 
        public static boolean isValidSubsequence(List<Integer> array, List<Integer> sequence) {
            int seqIdx = 0;
            for (var value : array) {
                if (seqIdx == sequence.size()) {
                    break;
                }
                if (sequence.get(seqIdx) == value) {
                    seqIdx++;
                }
            }
            return seqIdx == sequence.size();
        }
    }

Given BST and an Integer Value, find the closest value to the target value(12).

Solution: Binary search(while loop/recursion)

  1. Two Integer target and closest
  2. compare target and cur.value to decide go cur.left ot cur.right

Time complexity:O(log(n)) Space complexity: O(1)

While Loop:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
 // Average: O(log(n)) time | O(1) space
 // Worst: O(n) time | O(1) space
 function findClosestValueInBst(tree, target) {
     return findClosestValueInBstHelper(tree, target, Infinity);
 }

 function findClosestValueInBstHelper(tree, target, closest) {
     let currentNode = tree;
     while (currentNode !== null) {
         if (Math.abs(target - closest) > Math.abs(target - currentNode.val)) {
             closest = currentNode.value;
         }
         if (target < currentNode.value) {
             currentNode = currentNode.left;
         } else if (target > currentNode.value) {
             currentNode = currentNode.right;
         } else {
             break;
         }
     }
     return closest;
 }

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
class Program {
        // Average: O(log(n)) time | O(1) space // Worst: O(n) time | O(1) space
        public static int findClosestValueInBst(BST tree, int target) {
            return findClosestValueInBst(tree, target, Double.MAX_VALUE);
        }

        public static int findClosestValueInBst(BST tree, int target, double closest) {
            BST currentNode = tree;
            while (currentNode != null) {
                if (Math.abs(target - closest) > Math.abs(target - currentNode.value) {
                    closest = currentNode.value;
                }
                if (target < currentNode.value) {
                    currentNode = currentNode.left;
                } else if (target > currentNode.value) {
                    currentNode = currentNode.right;
                } else {
                    break;
                }
                return (int) closest;
            }
        }

        static class BST {
            public int value;
            public BST left;
            public BST right;

            public BST(int value) {
                this.value = value;
            }
        }

    }

Recursion:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
// Average: O(log(n)) time | O(log(n)) space
// Worst: O(n) time | O(n) space
function findClosestValueInBst(tree, target) {
    return findClosestValueInBstHelper(tree, target, Infinity);
}

function findClosestValueInBstHelper(tree, target, closest) {
    if (tree === null) return closest;
    if (Math.abs(target - closest) > Math.abs(target - tree.value)) {
        closest = tree.value;
    }
    if (target < tree.value) {
        return findClosestValueInBstHelper(tree.left, target, closest);
    } else if (target > tree.value) {
        return findClosestValueInBstHelper(tree.right, target, closest);
    } else {
        return closest;
    }
}

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
class Program {
        // Average: O(log(n)) time | O(log(n)) space // Worst: O(n) time | O(n) space
        public static int findClosestValueInBst(BST tree, int target) {
            return findClosestValueInBst(tree, target, Double.MAX_VALUE);
        }

        public static int findClosestValueInBst(BST tree, int target, double closest) {
            if (Math.abs(target - closest) > Math.abs(target - tree.value)) {
                closest = tree.value;
            }
            if (target < tree.value && tree.left != null) {
                return findClosestValueInBst(tree.left, target, closest);
            } else if (target > tree.value && tree.right != null) {
                return findClosestValueInBst(tree.right, target, closest);
            } else {
                return (int) closest;
            }
        }

        static class BST {
            public int value;
            public BST left;
            public BST right;

            public BST(int value) {
                this.value = value;
            }
        }
    }
Path Sum

Find all brach sum in the tree added into a list

Solution: Recursion

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class BinaryTree {
    constructor(value) {
        this.value = value;
        this.left = null;
        this.right = null;
    }
}
// O(n) time | O(n) space - where n is the number of nodes in the Binay tree
function branchSums(root) {
    const sums = [];
    calculateBranchSums(root, 0, sums);
    return sums;
}

function calculateBranchSums(node, runningSum, sums) {
    if (!node) return;
    const newRunningSum = runningSum + node.value;
    if (!node.left && !node.right) {
        sums.push(newRunningSum);
        return;
    }
    calculateBranchSums(node.left, newRunningSum, sums);
    calculateBranchSums(node.right, newRunningSum, sums);
}

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
class Program {
        public static class BinaryTree {
            int value;
            BinaryTree left;
            BinaryTree right;

            BinaryTree(int value) {
                this.value = value;
                this.left = null;
                this.right = null;
            }
        }

        // O(n) time | O(n) space - where n is the number of nodes in the Bi
        public static List<Integer> branchSums(BinaryTree root) {
            List<Integer> sums = new ArrayList<Integer>();
            calculateBranchSums(root, 0, sums);
            return sums;
        }

        public static void calculateBranchSums(BinaryTree node, int runningSum, List<Integer> sums) {
            if (node == null) return;
            int newRunningSum = runningSum + node.value;
            if (node.left == null && node.right == null) {
                sums.add(newRunningSum);
                return;
            }
        }
    }
Find total depth of each node in Binary Tree.
104. Maximum Depth of Binary Tree

Solution: Recursion, Stack

Recursion:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
  //Average case: when the tree is balanced
  // O(n) time | O(h) space - where n is the number of nodes in
  // the Binary Tree and h is the height of the Binary Tree
  function nodeDepths(root, depth = 0) {
      if (root === null) return 0;
      return depth + nodeDepths(root.left, depth + 1) + nodeDepths(root.right, depth + 1);
  }
  // This is the class of the input binary tree.

  class BinaryTree {
      constructor(value) {
          this.value = value;
          this.left = null;
          this.right = null;
      }
  }

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
class Program {
    // Average case: when the tree is balanced
    // O(n) time | O(h) space - where n is the number of nodes in
    // the Binary Tree and h is the height of the Binary Tree
    public static int nodeDepths(BinaryTree root) {
        return nodeDepthsHelper(root, 0);
    }

    public static int nodeDepthsHelper(BinaryTree root, int depth) {
        if (root == null) return 0;
        return depth + nodeDepthsHelper(root.left, depth + 1) + nodeDepthsHelper(root.right, depth + 1);
    }

    static class BinaryTree {
        int value;
        BinaryTree left;
        BinaryTree right;

        public BinaryTree(int value) {
            this.value = value;
            left = null;
            right = null;
        }
    }
}

Stack:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
// Average case: when the tree is balanced
// O(n) time | O(h) space - where n is the number of nodes in
// the Binary Tree and h is the height of the Binary Tree
function nodeDepths(root) {
    let sumOfDepths = 0;
    const stack = [{
        node: root,
        depth: 0
    }];
    while (stack.length > 0) {
        const {
            node,
            depth
        } = stack.pop();
        if (node === null) continue;
        sumOfDepths += depth;
        stack.push({
            node: node.left,
            depth: depth + 1
        });
        stack.push({
            node: node.right,
            depth: depth + 1
        });
    }
    return sumOfDepths;
}

// This is the class of the input binary tree.
class BinaryTree {
    constructor(value) {
        this.value = value;
        this.left = null;
        this.right = null;
    }
}

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
class Program {
    // Average case: when the tree is balanced
    // O(n) time | O(h) space - where n is the number of nodes in
    // the Binary Tree and h is the height of the Binary Tree
    public static int nodeDepths(BinaryTree root) {
        int sumOfDepths = 0;
        List<Level> stack = new ArrayList<Level>();
        stack.add(new Level(root, 0));
        while (stack.size() > 0) {
            Level top = stack.remove(stack.size() - 1);
            BinaryTree node = top.root;
            int depth = top.depth;
            if (node == null) continue;
            sumOfDepths += depth;
            stack.add(new Level(node.left, depth + 1));
            stack.add(new Level(node.right, depth + 1));
        }
        return sumOfDepths;
    }

    static class Level {
        public BinaryTree root;
        int depth;

        public Level(BinaryTree root, int depth) {
            this.root = root;
            this.depth = depth;
        }
    }

    static class BinaryTree {
        int value;
        BinaryTree left;
        BinaryTree right;

        public BinaryTree(int value) {
            this.value = value;
            left = null;
            right = null;
        }
    }
}

Solution: Recursion

Call  and go Children Node before resolve itself.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
class Node {
    constructor(name) {
        this.name = name;
        this.children = [];
    }
    addChild(name) {
        this.children.push(new Node(name));
        return this;
    }
    // O(v + e) time | O(v) space
    depthFirstSearch(array) {
        array.push(this.name);
        for (const child of this.children) {
            child.depthFirstSearch(array);
        }
        return array;
    }
}

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
class Program {
    static class Node {
        String name;
        List<Node> children = new ArrayList<Node>();

        public Node(String name) {
            this.name = name;
        }

        // O(v + e) time | O(v) space 
        public List<String> depthFirstSearch(List<String> array) {
            array.add(this.name);
            for (int i = 0; i < children.size(); i++) {
                children.get(i).depthFirstSearch(array);
            }
            return array;
        }

        public Node addChild(String name) {
            Node child = new Node(name);
            children.add(child);
            return this;
        }
    }
}

Data Structure:

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
class Node {
    public int value;
    public Node prev;
    public Node next;

    public Node(int value) {
        this.value = value;
    }
}

class Program {
    static class DoublyLinkedList {
        public Node head;
        public Node tail;

        // O(1) time | O(1) space
        public void setHead(Node node) {
            if (head == null) {
                head = node;
                tail = node;
                return;
            }
            insertBefore(head, node);
        }

        // O(1) time | O(1) space
        public void setTail(Node node) {
            if (tail == null) {
                setHead(node);
                return;
            }

            insertAfter(tail, node);

        }

        // O(1) time | O(1) space
        public void insertBefore(Node node, Node nodeToInsert) {
            if (nodeToInsert == head && nodeToInsert == tail) return;
            remove(nodeToInsert);
            nodeToInsert.prev = node.prev;
            nodeToInsert.next = node;
            if (node.prev == null) {
                head = nodeToInsert;
            } else {
                node.prev.next = nodeToInsert;
            }
            node.prev = nodeToInsert;
        }

        // O(1) time | O(1) space
        public void insertAfter(Node node, Node nodeToInsert) {
            if (nodeToInsert == head && nodeToInsert == tail) return;
            remove(nodeToInsert);
            nodeToInsert.prev = node;
            nodeToInsert.next = node.next;
            if (node.next == null) {
                tail = nodeToInsert;
            } else {
                node.next.prev = nodeToInsert;
            }
            node.next = nodeToInsert;
        }

        // O(p) time | O(1) space
        public void insertAtPosition(int position, Node nodeToInsert) {
            if (position == 1) {
                setHead(nodeToInsert);
                return;
            }
            Node node = head;
            int currentPosition = 1;
            while (node != null && currentPosition++ != position) node = nod if (node != null) {
                insertBefore(node, nodeToInsert);
            } else {
                setTail(nodeToInsert);
            }
        }

        // O(n) time | O(1) space
        public void removeNodesWithValue(int value) {
            Node node = head;
            while (node != null) {
                Node nodeToRemove = node;
                node = node.next;
                if (nodeToRemove.value == value) remove(nodeToRemove);
            }
        }

        // O(1) time | O(1) space
        public void remove(Node node) {
            if (node == head) head = head.next;
            if (node == tail) tail = tail.prev;
            removeNodeBindings(node);
        }

        // O(n) time | O(1) space
        public boolean containsNodeWithValue(int value) {
            Node node = head;
            while (node != null && node.value != value) node = node.next;
            return node != null;
        }

        public void removeNodeBindings(Node node) {
            if (node.prev != null) node.prev.next = node.next;
            if (node.next != null) node.next.prev = node.prev;
            node.prev = null;
            node.next = null;
        }
    }
Formula :

  1. when n>2   Fib(n)=Fib(n-1)+Fib(n-2)
  2. if n=2 return 1
  3. if n=1 return 0

Solution to get Fib(n): recursion , Iteration (better)

1. recursion

Time complexity: O(n)            Space Complexity: O(n)

When we want to Fib(n), use recursion function, and memorized calculated Fib(i)  in HashTable.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
// O(2^n) time | O(n) space
function getNthFib(n) {
    if (n === 2) {
        return 1;
    } else if (n === 1) {
        return 0;
    } else {
        return getNthFib(n - 1) + getNthFib(n - 2);
    }
}

Java Code:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
class Program {
    // O(n) time | O(n) space
    public static int getNthFib(int n) {
        Map<Integer, Integer> memoize = new HashMap<Integer, Integer>();
        memoize.put(1, 0);
        memoize.put(2, 1);
        return getNthFib(n, memoize);
    }

    public static int getNthFib(int n, Map<Integer, Integer> memoize) {
        if (memoize.containsKey(n)) {
            return memoize.get(n);
        } else {
            memoize.put(n, getNthFib(n - 1, memoize) + getNthFib(n - 2, memoize); 
            return memoize.get(n);
        }
    }
}

2.iteration (better)

Example: Fib(4)

  • initial fixed array [0,1]
  • Fib(2)=0+1=1    update array[1,1]   (move index 1 to 0, Fib(2) = index 1)
  • Fib(3)=1+1=2    update array[1,2]
  • Fib(4)=1+2=3    return Fib(4)

Time complexity: O(n)             Space complexity: O(1)


JavaScript:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
// O(n) time | O(n) space
function getNthFib(n, memoize = {
    1: 0,
    2: 1
}) {
    if (n in memoize) {
        return memoize[n];
    } else {
        memoize[n] = getNthFib(n - 1, memoize) + getNthFib(n - 2, memoize)
        return memoize[n];
    }
}

Java Code:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
class Program {
    // O(n) time | O(1) space 
    public static int getNthFib(int n) {
        int[] lastTwo = {0, 1};
        int counter = 3;
        while (counter <= n) {
            int nextFib = lastTwo[0] + lastTwo[1];
            lastTwo[0] = lastTwo[1];
            lastTwo[1] = nextFib;
            counter++;
        }
        return n > 1 ? lastTwo[1] : lastTwo[0];
    }
}

While Loop

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
// O(n) time | O(1) space
function getNthFib(n) {
    const lastTwo = [0, 1];
    let counter = 3;
    while (counter <= n) {
        const nextFib = lastTwo[0] + lastTwo[1];
        lastTwo[0] = lastTwo[1];
        lastTwo[1] = nextFib;
        counter++;
    }
    returnn > 1 ? lastTwo[1] : lastTwo[0];
}

Product Sum is sum of all the elements in the array.

 Recursion:

  • [7,-1]   sum=6, m(depth)=2
  • [-13,8]   sum=5, m=3
  • Time = O(N), Space = O(D)   D=depth of the array  there is 3.

JavaScript:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
function productSum(array, multiplier = 1) {
    letsum = 0;
    for (const element of array) {
        if (Array.isArray(element)) {
            sum += productSum(element, multiplier + 1);
        } else {
            sum += element;
        }
    }
    return sum * multiplier;
}

Java:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
class Program {
    // O(n) time | O(d) space - where n is the total number of elements // including sub-elements, and d is the greatest depth of "special"
    public static int productSum(List<Object> array) {
        return productSumHelper(array, 1);
    }

    public static int productSumHelper(List<Object> array, int multiplie int sum=0;for(Object el:array) {
        if (el instanceof ArrayList) {
            @SuppressWarnings("unchecked") 
            ArrayList<Object> ls = (ArrayList<Object>) el;
            sum += productSumHelper(ls, multiplier + 1);
        } else {
            sum += (int) el;
        }
        return sum *multiplier;
    }
}

Give a sorted array, use Binary Search to find a value val in O(LogN) time complexity, and return its index.

Solution: Left Pointer and Right Pointer

  • while(left<=right)
  • index middle=start + ( end – start )/2

JavaScript-Recommend(while loop):

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
// O(log(n)) time | O(1) space
function binarySearch(array, target) {
    return binarySearchHelper(array, target, 0, array.length - 1);
}

function binarySearchHelper(array, target, left, right) {
    while (left <= right) {
        const middle = Math.floor((left + right) / 2);
        const potentialMatch = array[middle];
        if (target === potentialMatch) {
            return middle;
        } else if (target < potentialMatch) {
            right = middle - 1;
        } else {
            left = middle + 1;
        }
    }
    return -1;
}

 

JavaScript(Recursion):

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
// O(log(n)) time | O(log(n)) space
function binarySearch(array, target) {
    return binarySearchHelper(array, target, 0, array.length - 1);
}

function binarySearchHelper(array, target, left, right) {
    if (left > right) return -1;
    const middle = Math.floor((left + right) / 2);
    const potentialMatch = array[middle];
    if (target === potentialMatch) {
        return middle;
    } else if (target < potentialMatch) {
        return binarySearchHelper(array, target, left, middle - 1);
    } else {
        return binarySearchHelper(array, target, middle + 1, right);
    }
}

Java(Recursion):

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
class Program {
    // O(log(n)) time | O(1) space
    public static int binarySearch(int[] array, int target) {
        return binarySearch1(array, target, 0, array.length - 1);
    }
    
    public static int binarySearch1(int[] array, int target, int left, int right) {
        while (left <= right) {
            int middle = left+(right-left)/2;
            int potentialMatch = array[middle];
            if (target == potentialMatch) {
                return middle;
            } else if (target < potentialMatch) {
                right = middle - 1;
            } else {
                left = middle + 1;
            }
        }
        return -1;
    }
}

Problem: Give a unsorted array, and return three largest numbers.

Solution: Heap/Fixed Length of array

Fixed Length of array:

  • initial  int[] res ={INT_MIN,INT_MIN,INT_MIN}
  • traversal given array to keep three largest in res.

JavaScript:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// O(n) time | O(1) space
function findThreeLargestNumbers(array) {
    const threeLargest = [null, null, null];
    for (const num of array) {
        updateLargest(threeLargest, num);
    }
    return threeLargest;
}

function updateLargest(threeLargest, num) {
    if (threeLargest[2] === null || num > threeLargest[2]) {
        shiftAndUpdate(threeLargest, num, 2);
    } else if (threeLargest[1] === null || num > threeLargest[1]) {
        shiftAndUpdate(threeLargest, num, 1);
    } else if (threeLargest[0] === null || num > threeLargest[0]) {
        shiftAndUpdate(threeLargest, num, 0);
    }
}

function shiftAndUpdate(array, num, idx) {
    for (let i = 0; i <= idx; i++) {
        if (i === idx) {
            array[i] = num;
        } else {
            array[i] = array[i + 1];
        }
    }
}

 

Java:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
class Program {
    // O(n) time | O(1) space
    public static int[] findThreeLargestNumbers(int[] array) {
        int[] threeLargest = {Integer.MIN_VALUE, Integer.MIN_VALUE, Integer.MIN_VALUE}
        for (int num : array) {
            updateLargest(threeLargest, num);
        }
        return threeLargest;
    }

    public static void updateLargest(int[] threeLargest, int num) {
        if (num > threeLargest[2]) {
            shiftAndUpdate(threeLargest, num, 2);
        } else if (num > threeLargest[1]) {
            shiftAndUpdate(threeLargest, num, 1);
        } else if (num > threeLargest[0]) {
            shiftAndUpdate(threeLargest, num, 0);
        }
    }

    public static void shiftAndUpdate(int[] array, int num, int idx) {
        for (int i = 0; i <= idx; i++) {
            if (i == idx) {
                array[i] = num;
            } else {
                array[i] = array[i + 1];
            }
        }
    }
}

Solution:  Time: O(n2)     Space:O(1)

  • First for loop can push the largest one to the index arr.length-1
  • Second round loop can push the 2nd Largest one to the index arr.length-2
  • So on so forth and Loop N times.

Example:
First Pass:
5 1 4 2 8 ) –> ( 1 5 4 2 8 ), Here, algorithm compares the first two elements, and swaps since 5 > 1.
( 1 5 4 2 8 ) –>  ( 1 4 5 2 8 ), Swap since 5 > 4
( 1 4 5 2 8 ) –>  ( 1 4 2 5 8 ), Swap since 5 > 2
( 1 4 2 5 8 ) –> ( 1 4 2 5 8 ), Now, since these elements are already in order (8 > 5), algorithm does not swap them.

Second Pass:
1 4 2 5 8 ) –> ( 1 4 2 5 8 )
( 1 4 2 5 8 ) –> ( 1 2 4 5 8 ), Swap since 4 > 2
( 1 2 4 5 8 ) –> ( 1 2 4 5 8 )
( 1 2 4 5 8 ) –>  ( 1 2 4 5 8 )
Now, the array is already sorted, but our algorithm does not know if it is completed. The algorithm needs one whole pass without any swap to know it is sorted.

Third Pass:
1 2 4 5 8 ) –> ( 1 2 4 5 8 )
( 1 2 4 5 8 ) –> ( 1 2 4 5 8 )
( 1 2 4 5 8 ) –> ( 1 2 4 5 8 )
( 1 2 4 5 8 ) –> ( 1 2 4 5 8 )

Java code:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
class Program {
    // Best: O(n) time | O(1) space // Average: O(n^2) time | O(1) space
    // Worst: O(n^2) time | O(1) space
    public static int[] bubbleSort(int[] array) {
        if (array.length == 0) {
            return new int[]{};
        }
        boolean isSorted = false;
        int counter = 0;
        while (!isSorted) {
            isSorted = true;
            for (int i = 0; i < array.length - 1 - counter; i++) {
                if (array[i] > array[i + 1]) {
                    swap(i, i + 1, array);
                    isSorted = false;
                }
            }
            counter++;
        }
        return array;
    }

    public static void swap(int i, int j, int[] array) {
        int temp = array[j];
        array[j] = array[i];
        array[i] = temp;
    }
}
Algorithm
To sort an array of size n in ascending order:
1: Iterate from arr[1] to arr[n] over the array.
2: Compare the current element (key) to its predecessor.
3: If the key element is smaller than its predecessor, compare it to the elements before. Move the greater elements one position up to make space for the swapped element.

JavaScript:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
// Best: O(n) time | O(1) space
// Average: O(n^2) time | O(1) space // Worst: O(n^2) time | O(1) space 
function insertionSort(array) {
    for (let i = 1; i < array.length; i++) {
        let j = i;
        while (j > 0 && array[j] < array[j - 1]) {
            swap(j, j - 1, array);
            j -= 1;
        }
    }
    return array;
}

function swap(i, j, array) {
    const temp = array[j];
    array[j] = array[i];
    array[i] = temp;
}

 

Java code:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class Program {
    // Best: O(n) time | O(1) space
    // Average: O(n^2) time | O(1) space
    // Worst: O(n^2) time | O(1) space
    public static int[] insertionSort(int[] array) {
        if (array.length == 0) {
            return new int[]{};
        }
        for (int i = 1; i < array.length; i++) {
            int j = i;
            while (j > 0 && array[j] < array[j - 1]) {
                swap(j, j - 1, array);
                j -= 1;
            }
        }
        return array;
    }

    public static void swap(int i, int j, int[] array) {
        int temp = array[j];
        array[j] = array[i];
        array[i] = temp;
    }
}

Algorithm:

The selection sort algorithm sorts an array by repeatedly finding the minimum element (considering ascending order) from unsorted part and putting it at the beginning. The algorithm maintains two subarrays in a given array.

1) The subarray which is already sorted.
2) Remaining subarray which is unsorted.

In every iteration of selection sort, the minimum element (considering ascending order) from the unsorted subarray is picked and moved to the sorted subarray.

PS: Bubble sort , insertion sort and selection sort may not most efficient sorting algorithm, but they are easy to implement.
Time: O(n)   Space: O(1)

 

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
class Program {
    // Best: O(n^2) time | O(1) space
    // Average: O(n^2) time | O(1) space
    // Worst: O(n^2) time | O(1) space
    public static int[] selectionSort(int[] array) {
        if (array.length == 0) {
            return new int[]{};
        }
        int startIdx = 0;
        while (startIdx < array.length - 1) {
            int smallestIdx = startIdx;
            for (int i = startIdx + 1; i < array.length; i++) {
                if (array[smallestIdx] > array[i]) {
                    smallestIdx = i;
                }
            }
            swap(startIdx, smallestIdx, array);
            startIdx++;
        }
        return array;
    }

    public static void swap(int i, int j, int[] array) {
        int temp = array[j];
        array[j] = array[i];
        array[i] = temp;
    }
}

Solution: Two Pointers

  1. Left Pointer=0, Right Pointer= arr.length-1
  2. if ( arr[Left]=arr[Right])  keep moving to the middle, else return false

JavaScript:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
// O(n) time | O(1) space
function isPalindrome(string) {
    let leftIdx = 0;
    let rightIdx = string.length - 1;
    while (leftIdx < rightIdx) {
        if (string[leftIdx] !== string[rightIdx]) return false;
        leftIdx++;
        rightIdx--;
    }
    return true;
}

 
Java:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
class Program {
    // O(n) time | O(1) space 
    public static boolean isPalindrome(String str) {
        int leftIdx = 0;
        int rightIdx = str.length() - 1;
        while (leftIdx < rightIdx) {
            if (str.charAt(leftIdx) != str.charAt(rightIdx)) {
                return false;
            }
            leftIdx++;
            rightIdx--;
        }
        return true;
    }
}
Given String “zhy” and integer value 2. Shifted by 2 = “zab”

A:65   Z:90

a:97   z:122

JavaScript:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
// O(n) time | O(n) space
function caesarCipherEncryptor(string, key) {
    const newLetters = [];
    const newKey = key % 26;
    const alphabet = 'abcdefghijklmnopqrstuvwxyz'.split('');
    for (const letter of string) {
        newLetters.push(getNewLetter(letter, newKey, alphabet));
    }
    return newLetters.join('');
}

function getNewLetter(letter, key, alphabet) {
    const newLetterCode = alphabet.indexOf(letter) + key;
    return newLetterCode <= 25 ? alphabet[newLetterCode] : alphabet[-1 + newLetterCode % 25];
}

 

Java code:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
class Program {
    // O(n) time | O(n) space
    public static String caesarCypherEncryptor(String str, int key) {
        char[] newLetters = new char[str.length()];
        int newKey = key % 26;
        String alphabet = "abcdefghijklmnopqrstuvwxyz";
        for (int i = 0; i < str.length(); i++) {
            newLetters[i] = getNewLetter(str.charAt(i), newKey, alphabet);
        }
        return new String(newLetters);
    }
    public static char getNewLetter(char letter, int key, String alphabet) {
        int newLetterCode = alphabet.indexOf(letter) + key;
        return newLetterCode <= 25 ? alphabet.charAt(newLetterCode) : alphabet.charAt(-1 + newLetterCode % 25);
    }
}

Middle
Given an array nums of n integers, are there elements a, b, c in nums such that a + b + c = 0? Find all unique triplets in the array which gives the sum of zero. Notice that the solution set must not contain duplicate triplets.

Solution:  Two Pointers | O(n^2) time | O(n) space

  1. Sort the array in ascending order.
  2. for loop to traverse array,  initial Left=i+1, Right=arr.length-1
  3. curSum = arr[i] + arr[left] + arr[right]
  4. while(left<right)
  5. if (curSum>target) , right–, else left++
  6. if(curSum==target)  add { arr[i], arr[left], arr[right] } to result List, then right– && left++

JavaScript Code:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
// O(n^2) time | O(n) space
function threeNumberSum(array, targetSum) {
    array.sort((a, b) => a - b);
    const triplets = [];
    for (let i = 0; i < array.length - 2; i++) {
        let left = i + 1;
        let right = array.length - 1;
        while (left < right) {
            const currentSum = array[i] + array[left] + array[right];
            if (currentSum === targetSum) {
                triplets.push([array[i], array[left], array[right]]);
                left++;
                right--;
            } else if (currentSum < targetSum) {
                left++;
            } else if (currentSum > targetSum) {
                right--;
            }
        }
    }
    return triplets;
}

Java Code:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
class Program {
    // O(n^2) time | O(n) space 
    public static List<Integer[]> threeNumberSum(int[] array, int targetSum) {
        Arrays.sort(array);
        List<Integer[]> triplets = new ArrayList<Integer[]>();
        for (int i = 0; i < array.length - 2; i++) {
            int left = i + 1;
            int right = array.length - 1;
            while (left < right) {
                int currentSum = array[i] + array[left] + array[right];
                if (currentSum == targetSum) {
                    Integer[] newTriplet = {array[i], array[left], array[right]};
                    triplets.add(newTriplet);
                    left++;
                    right--;
                } else if (currentSum < targetSum) {
                    left++;
                } else if (currentSum > targetSum) {
                    right--;
                }
            }
        }
        return triplets;
    }
}
Given two arrays of integers, compute the pair of values (one value in each array) with the smallest (non-negative) difference. Return the difference.

Examples :
1
2
3
4
Input : 
A[] = {1, 3, 15, 11, 2} 
B[] = {23, 127, 235, 19, 8} 
Output : 3 That is, the pair (11, 8)

Solution: Two Pointers || Time: O( N log( N ) + M log( M )) | Space: O( 1 )

  1. Sort two array A, B with length N, M in ascending order.
  2. while ( ismallest to get min difference.
  3. Start two pointers i, j from A[ 0 ], B[ 0 ], then compare pointers
  4. if A[ i ] < B[ j ], i++, else j++
  5. if A[ i ] = B[ j ]  return pair ( A[ i ], B[ j ] )

JavaScript Code:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// O(nlog(n) + mlog(m)) time | O(1) space
function smallestDifference(arrayOne, arrayTwo) {
    arrayOne.sort((a, b) => a - b);
    arrayTwo.sort((a, b) => a - b);
    let idxOne = 0;
    let idxTwo = 0;
    let smallest = Infinity;
    let current = Infinity;
    let smallestPair = [];
    while (idxOne < arrayOne.length && idxTwo < arrayTwo.length) {
        let firstNum = arrayOne[idxOne];
        let secondNum = arrayTwo[idxTwo];
        if (firstNum < secondNum) {
            current = secondNum - firstNum;
            idxOne++;
        } else if (secondNum < firstNum) {
            current = firstNum - secondNum;
            idxTwo++;
        } else {
            return [firstNum, secondNum];
        }
        if (smallest > current) {
            smallest = current;
            smallestPair = [firstNum, secondNum];
        }
    }
    return smallestPair;
}

Java Code:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
class Program {
    // O(nlog(n) + mlog(m)) time | O(1) space
    public static int[] smallestDifference(int[] arrayOne, int[] arrayTwo) {
        Arrays.sort(arrayOne);
        Arrays.sort(arrayTwo);
        int idxOne = 0;
        int idxTwo = 0;
        int smallest = Integer.MAX_VALUE;
        int current = Integer.MAX_VALUE;
        int[] smallestPair = new int[2];
        while (idxOne < arrayOne.length && idxTwo < arrayTwo.length) {
            int firstNum = arrayOne[idxOne];
            int secondNum = arrayTwo[idxTwo];
            if (firstNum < secondNum) {
                current = secondNum - firstNum;
                idxOne++;
            } else if (secondNum < firstNum) {
                current = firstNum - secondNum;
                idxTwo++;
            } else {
                return new int[]{firstNum, secondNum};
            }
            if (smallest > current) {
                smallest = current;
                smallestPair = new int[]{firstNum, secondNum};
            }
        }
        return smallestPair;
    }
}
Given an array and Integer toMove, move all the toMoves  in array to the end in O(1) space complexity.

Example:

1
2
The original list is : ['3', '5', '7', '9', '11'] ToMove : 5
The modified element moved list is : ['3', '7', '9', '11', '5']

Solution: Two Pointers   || Time : O ( N ) | Space : O ( 1 )

  1. i = 0, j = arr.length – 1
  2. while( i < j )
  3.      while( i < j and arr [ j ] = toMove)  then j–
  4.            if ( arr[ i ]==toMove ) then swap ( arr[ i ] , arr[ j ] )  ,  i++
  5. return array

JavaScript Code:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
// O(n) time | O(1) space - where n is the length of the array 
function moveElementToEnd(array, toMove) {
    let i = 0;
    let j = array.length - 1;
    while (i < j) {
        while (i < j && array[j] === toMove) j--;
        if (array[i] === toMove) swap(i, j, array);
        i++;
    }
    return array;
}

function swap(i, j, array) {
    const temp = array[j];
    array[j] = array[i];
    array[i] = temp;
}

Java Code:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
class Program {
    // O(n) time | O(1) space - where n is the length of the array
    public static List<Integer> moveElementToEnd(List<Integer> array, int toMove) {
        int i = 0;
        int j = array.size() - 1;
        while (i < j) {
            while (i < j && array.get(j) == toMove) j--;
            if (array.get(i) == toMove) swap(i, j, array);
            i++;
        }
        return array;
    }

    public static void swap(int i, int j, List<Integer> array) {
        int temp = array.get(j);
        array.set(j, array.get(i));
        array.set(i, temp);
    }
}
Give an array, return true or false if it’s Monotonic Array. Monotonic  can be entirely Non-Decreasing or Non-Increasing.

Tricky: Array may contain duplicate Integer.

896. Monotonic Array

Solution:  || Time : O ( N ) | Space : O ( 1 )

  1. determine the direction ( downward or upward trending )

JavaScript Code:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
// O(n) time | O(1) space - n = length of the array 
function isMonotonic(array) {
    let isNonDecreasing = true;
    let isNonIncreasing = true;
    for (let i = 1; i < array.length; i++) {
        if (array[i] < array[i - 1]) isNonDecreasing = false;
        if (array[i] > array[i - 1]) isNonIncreasing = false;
    }
    return isNonDecreasing || isNonIncreasing;
}

Java Code:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
class Program {
    // O(n) time | O(1) space - where n is the length of the array
    public static boolean isMonotonic(int[] array) {
        boolean isNonDecreasing = true;
        boolean isNonIncreasing = true;
        for (int i = 1; i < array.length; i++) {
            if (array[i] < array[i - 1]) {
                isNonDecreasing = false;
            }
            if (array[i] > array[i - 1]) {
                isNonIncreasing = false;
            }
        }
        return isNonDecreasing || isNonIncreasing;
    }
}
Given an m x n matrix, return all elements of the matrix in spiral order.  N: total number of vertices

54. Spiral Matrix

54. Spiral Matrix

Solution:  Iteration  || Time : O ( N ) | Space : O ( 1 ) / Recursion   || Time : O ( N ) | Space : O ( N )

  1. initial four pointers:
  2. startColomn = 0, endColomn = arr[0].length - 1, startRow = 0, endRow = arr.length-1
  3. use iterative method (optimal) or recursive method to traverse 2D array.

Shrink to calculate inner perimeter:

Iterative method:

JavaScript Code:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
// O(n) time | O(n) space - where n is the total number of elements in the array 
function spiralTraverse(array) {
    const result = [];
    let startRow = 0,
        endRow = array.length - 1;
    let startCol = 0,
        endCol = array[0].length - 1;
    while (startRow <= endRow && startCol <= endCol) {
        for (let col = startCol; col <= endCol; col++) {
            result.push(array[startRow][col]);
        }
        for (let row = startRow + 1; row <= endRow; row++) {
            result.push(array[row][endCol]);
        }
        for (let col = endCol - 1; col >= startCol; col--) {
            if (startRow === endRow) break;
            result.push(array[endRow][col]);
        }
        for (let row = endRow - 1; row > startRow; row--) {
            if (startCol === endCol) break;
            result.push(array[row][startCol]);
        }
        startRow++;
        endRow--;
        startCol++;
        endCol--;
    }
    return result;
}

Java Code:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
class Program {
    // O(n) time | O(n) space - where n is the total number of elements in the array 
    public static List<Integer> spiralTraverse(int[][] array) {
        if (array.length == 0) return new ArrayList<Integer>();
        List<Integer> result = new ArrayList<Integer>();
        int startRow = 0;
        int endRow = array.length - 1;
        int startCol = 0;
        int endCol = array[0].length - 1;
        while (startRow <= endRow && startCol <= endCol) {
            for (int col = startCol; col <= endCol; col++) {
                result.add(array[startRow][col]);
            }
            for (int row = startRow + 1; row <= endRow; row++) {
                result.add(array[row][endCol]);
            }
            for (int col = endCol - 1; col >= startCol; col--) {
                if (startRow == endRow) break;
                result.add(array[endRow][col]);
            }
            for (int row = endRow - 1; row > startRow; row--) {
                if (startCol == endCol) break;
                result.add(array[row][startCol]);
            }
            startRow++;
            endRow--;
            startCol++;
            endCol--;
        }
        return result;
    }
}

Recursive method:

JavaScript Code:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
// O(n) time | O(n) space - where n is the total number of elements in the array 
function spiralTraverse(array) {
    const result = [];
    let startRow = 0,
        endRow = array.length - 1;
    let startCol = 0,
        endCol = array[0].length - 1;
    while (startRow <= endRow && startCol <= endCol) {
        for (let col = startCol; col <= endCol; col++) {
            result.push(array[startRow][col]);
        }
        for (let row = startRow + 1; row <= endRow; row++) {
            result.push(array[row][endCol]);
        }
        for (let col = endCol - 1; col >= startCol; col--) {
            if (startRow === endRow) break;
            result.push(array[endRow][col]);
        }
        for (let row = endRow - 1; row > startRow; row--) {
            if (startCol === endCol) break;
            result.push(array[row][startCol]);
        }
        startRow++;
        endRow--;
        startCol++;
        endCol--;
    }
    return result;
}

Java Code:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
class Program {
    // O(n) time | O(n) space - where n is the total number of elements in the array
    public static List<Integer> spiralTraverse(int[][] array) {
        if (array.length == 0) return new ArrayList<Integer>();
        List<Integer> result = new ArrayList<Integer>();
        spiralFill(array, 0, array.length - 1, 0, array[0].length - 1, result);
        return result;
    }

    public static void spiralFill(int[][] array,
                                  int startRow, int endRow, int startCol,
                                  int endCol, ArrayList<Integer> result) {
        if (startRow > endRow || startCol > endCol) {
            return;
        }
        for (int col = startCol; col <= endCol; col++) {
            result.add(array[startRow][col]);
        }
        for (int row = startRow + 1; row <= endRow; row++) {
            result.add(array[row][endCol]);
        }
        for (int col = endCol - 1; col >= startCol; col--) {
            if (startRow == endRow) break;
            result.add(array[endRow][col]);
        }
        for (int row = endRow - 1; row >= startRow + 1; row--) {
            if (startCol == endCol) break;
            result.add(array[row][startCol]);
        }
        spiralFill(array, startRow + 1, endRow - 1, startCol + 1, endCol - 1, result);
    }
}
Peak i definitions:

  • arr[0] < arr[1] < ... < arr[i - 1] < arr[i]
  • arr[i] > arr[i + 1] > ... > arr[arr.length - 1]

845. Longest Mountain in Array

Solution: Time O(n) | Space O(1)

  1. Iterate array to Find peeks in the array, once find a peek, expand its left and right to see how far this peek goes, then save its length to compare next length of finding peek. O(n)

Old Method:

  1. Iterate array to Find all peeks in the array.  O(n)
  2. compare each peek length to get longest peek. O(n)

Example: Traversing the array, find 4 is one peek, expand its left and right to get length=3, save it and continue, find 10 is peek, expand to get it length =6, compare Math.max(4,6) =6…To the end of array. return the length.

JavaScript Code:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// O(n) time | O(1) space - where n is the length of the input array 
function longestPeak(array) {
    let longestPeakLength = 0;
    let i = 1;
    while (i < array.length - 1) {
        const isPeak = array[i - 1] < array[i] && array[i + 1] < array[i];
        if (!isPeak) {
            i++;
            continue;
        }
        let leftIdx = i - 2;
        while (leftIdx >= 0 && array[leftIdx] < array[leftIdx + 1]) {
            leftIdx--;
        }
        let rightIdx = i + 2;
        while (rightIdx < array.length && array[rightIdx] < array[rightIdx - 1]) {
            rightIdx++;
        }
        const currentPeakLength = rightIdx - leftIdx - 1;
        longestPeakLength = Math.max(longestPeakLength, currentPeakLength);
        i = rightIdx;
    }
    return longestPeakLength;
}

Java Code:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
class Program {
    // O(n) time | O(1) space - where n is the length of the input array 
    public static int longestPeak(int[] array) {
        int longestPeakLength = 0;
        int i = 1;
        while (i < array.length - 1) {
            boolean isPeak = array[i - 1] < array[i] && array[i] > array[i + 1];
            if (!isPeak) {
                i += 1;
                continue;
            }
            int leftIdx = i - 2;
            while (leftIdx >= 0 && array[leftIdx] < array[leftIdx + 1]) {
                leftIdx -= 1;
            }
            int rightIdx = i + 2;
            while (rightIdx < array.length && array[rightIdx] < array[rightIdx - 1]) {
                rightIdx += 1;
            }
            int currentPeakLength = rightIdx - leftIdx - 1;
            if (currentPeakLength > longestPeakLength) {
                longestPeakLength = currentPeakLength;
            }
            i = rightIdx;
        }
        return longestPeakLength;
    }
}
Problem : Return true or false to validate if it’s Binary Search Tree.

Leetcode Link

JavaScript Code:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
class BST {
    constructor(value) {
        this.value = value;
        this.left = null;
        this.right = null;
    }
}
// O(n) time | O(d) space 
function validateBst(tree) {
    return validateBstHelper(tree, -Infinity, Infinity);
}

function validateBstHelper(tree, minValue, maxValue) {
    if (tree === null) return true;
    if (tree.value < minValue || tree.value >= maxValue) return false;
    const leftIsValid = validateBstHelper(tree.left, minValue, tree.value);
    return leftIsValid && validateBstHelper(tree.right, tree.value, maxValue);
}
exports.BST = BST;
exports.validateBst = validateBst;

Java Code:

class Program {
    // O(n) time | O(d) space
    public static boolean validateBst(BST tree) {
        return validateBst(tree, Integer.MIN_VALUE, Integer.MAX_VALUE);
    }

    public static boolean validateBst(BST tree, int minValue, int maxValue) {
        if (tree.value < minValue || tree.value >= maxValue) {
            return false;
        }
        if (tree.left != null && !validateBst(tree.left, minValue, tree.value)) {
            return false;
        }
        if (tree.right != null && !validateBst(tree.right, tree.value, maxValue)) {
            return false;
        }
        return true;
    }

    static class BST {
        public int value;
        public BST left;
        public BST right;

        public BST(int value) {
            this.value = value;
        }
    }
}

Problem : use Pre-order, In-order,  Post-order to traverse a Binary Search Tree

Solution : Recursion

Pre-order:

function preorder(root)
   if not root: return
   print(root.val)
   preorder(root.left)
   preorder(root.right)

In-order:

function preorder(root)
   if not root: return
   preorder(root.left)
   print(root.val)
   preorder(root.right)

Post-order:

function preorder(root)
   if not root: return
   preorder(root.left)
   preorder(root.right)
   print(root.val)

JavaScript Code:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
// O(n) time | O(n) space
function inOrderTraverse(tree, array) {
    if (tree !== null) {
        inOrderTraverse(tree.left, array);
        array.push(tree.value);
        inOrderTraverse(tree.right, array);
    }
    return array;
}
// O(n) time | O(n) space
function preOrderTraverse(tree, array) {
    if (tree !== null) {
        array.push(tree.value);
        preOrderTraverse(tree.left, array);
        preOrderTraverse(tree.right, array);
    }
    return array;
}
// O(n) time | O(n) space
function postOrderTraverse(tree, array) {
    if (tree !== null) {
        postOrderTraverse(tree.left, array);
        postOrderTraverse(tree.right, array);
        array.push(tree.value);
    }
    return array;
}
exports.inOrderTraverse = inOrderTraverse;
exports.preOrderTraverse = preOrderTraverse;
exports.postOrderTraverse = postOrderTraverse;

Java Code:

class Program {
    // O(n) time | O(n) space
    public static List<Integer> inOrderTraverse(BST tree, List<Integer> array) {
        if (tree.left != null) {
            inOrderTraverse(tree.left, array);
        }
        array.add(tree.value);
        if (tree.right != null) {
            inOrderTraverse(tree.right, array);
        }
        return array;
    }

    // O(n) time | O(n) space
    public static List<Integer> preOrderTraverse(BST tree, List<Integer> array) {
        array.add(tree.value);
        if (tree.left != null) {
            preOrderTraverse(tree.left, array);
        }
        if (tree.right != null) {
            preOrderTraverse(tree.right, array);
        }
        return array;
    }

    // O(n) time | O(n) space
    public static List<Integer> postOrderTraverse(BST tree, List<Integer> array) {
        if (tree.left != null) {
            postOrderTraverse(tree.left, array);
        }
        if (tree.right != null) {
            postOrderTraverse(tree.right, array);
        }
        array.add(tree.value);
        return array;
    }

    static class BST {
        public int value;
        public BST left;
        public BST right;

        public BST(int value) {
            this.value = value;
        }
    }
}

Problem : Given a distinct Sorted array, build a Minimum Height BST

Solution : Recursion

Find the middle value as root Node A, then all the values in the left of root will be placed in the left of BST, and all the values in the right of root will be placed in the right of BST.  Use same function to find Left and Right Node of A

JavaScript Code:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
// O(n) time | O(n) space - where n is the length of the array 

function minHeightBst(array) {
    return constructMinHeightBst(array, 0, array.length - 1);
}

function constructMinHeightBst(array, startIdx, endIdx) {
    if (endIdx < startIdx) return null;
    const midIdx = Math.floor((startIdx + endIdx) / 2);
    const bst = new BST(array[midIdx]);
    bst.left = constructMinHeightBst(array, startIdx, midIdx - 1);
    bst.right = constructMinHeightBst(array, midIdx + 1, endIdx);
    return bst;
}
class BST {
    constructor(value) {
        this.value = value;
        this.left = null;
        this.right = null;
    }
    // We don't use this method for this solution.   
    insert(value) {
        if (value < this.value) {
            if (this.left === null) {
                this.left = new BST(value);
            } else {
                this.left.insert(value);
            }
        } else {
            if (this.right === null) {
                this.right = new BST(value);
            } else {
                this.right.insert(value);
            }
        }
    }
}

Java Code:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
class Program {
    
    // O(n) time | O(n) space - where n is the length of the array
    public static BST minHeightBst(List<Integer> array) {
        return constructMinHeightBst(array, 0, array.size() - 1);
    }

    public static BST constructMinHeightBst(List<Integer> array, int startIdx, int endIdx) {
        if (endIdx < startIdx) return null;
        int midIdx = (startIdx + endIdx) / 2;
        BST bst = new BST(array.get(midIdx));
        bst.left = constructMinHeightBst(array, startIdx, midIdx - 1);
        bst.right = constructMinHeightBst(array, midIdx + 1, endIdx);
        return bst;
    }

    static class BST {
        public int value;
        public BST left;
        public BST right;

        public BST(int value) {
            this.value = value;
            left = null;
            right = null;
        }
    }
}

Problem: invert the BST

Solution: While loop && Recursion

BFS the tree into queue, use queue to traverse it, level by level from top.

  1. poll root node from queue
  2. swap (root.left, root.right), add into queue
  3. repeat step one until queue is empty

While loop:
JavaScript:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
// O(n) time | O(n) space
function invertBinaryTree(tree) {
    const queue = [tree];
    while (queue.length) {
        const current = queue.shift();
        if (current === null) continue;
        swapLeftAndRight(current);
        queue.push(current.left);
        queue.push(current.right);
    }
}

function swapLeftAndRight(tree) {
    const left = tree.left;
    tree.left = tree.right;
    tree.right = left;
}

Recursion:
JavaScript:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
// O(n) time | O(d) space
function invertBinaryTree(tree) {
    if (tree === null) return;
    swapLeftAndRight(tree);
    invertBinaryTree(tree.left);
    invertBinaryTree(tree.right);
}

function swapLeftAndRight(tree) {
    const left = tree.left;
    tree.left = tree.right;
    tree.right = left;
}

Problem : Given an array with only positive integers, find max subset sum no adjacent

Solution: DP

Formula :

Java Code ( Optimal )   Use 3 Integers : Current = Max ( First , Second ) instead of DP array :

JavaScript:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
// O(n) time | O(1) space
function maxSubsetSumNoAdjacent(array) {
    if (!array.length) return 0;
    if (array.length === 1) return array[0];
    let second = array[0];
    let first = Math.max(array[0], array[1]);
    for (let i = 2; i < array.length; i++) {
        const current = Math.max(first, second + array[i]);
        second = first;
        first = current;
    }
    return first;
}

Java:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
class Program {
    // O(n) time | O(1) space
    public static int maxSubsetSumNoAdjacent(int[] array) {
        if (array.length == 0) {
            return 0;
        } else if (array.length == 1) {
            return array[0];
        }
        int second = array[0];
        int first = Math.max(array[0], array[1]);
        for (int i = 2; i < array.length; i++) {
            int current = Math.max(first, second + array[i]);
            second = first;
            first = current;
        }
        return first;
    }
}

Problem:

Formula:

Time Complexity (space in optimal solution based on 2*rows or 2*columns):

JavaScript(optimal):

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
// O(nm) time | O(min(n, m)) space
function levenshteinDistance(str1, str2) {
    const small = str1.length < str2.length ? str1 : str2;
    const big = str1.length >= str2.length ? str1 : str2;
    const evenEdits = [];
    const oddEdits = new Array(small.length + 1);
    for (let j = 0; j < small.length + 1; j++) {
        evenEdits.push(j);
    }
    for (let i = 1; i < big.length + 1; i++) {
        let currentEdits, previousEdits;
        if (i % 2 === 1) {
            currentEdits = oddEdits;
            previousEdits = evenEdits;
        } else {
            currentEdits = evenEdits;
            previousEdits = oddEdits;
        }
        currentEdits[0] = i;
        for (let j = 1; j < small.length + 1; j++) {
            if (big[i - 1] === small[j - 1]) {
                currentEdits[j] = previousEdits[j - 1];
            } else {
                currentEdits[j] = 1 + Math.min(previousEdits[j - 1], previousEdits[j], currentEdits[j - 1]);
            }
        }
    }
    return big.length % 2 === 0 ? evenEdits[small.length] : oddEdits[small.length];
}

Java Code :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class Program {
    // O(nm) time | O(nm) space
    public static int levenshteinDistance(String str1, String str2) {
        int[][] edits = new int[str2.length() + 1][str1.length() + 1];
        for (int i = 0; i < str2.length() + 1; i++) {
            for (int j = 0; j < str1.length() + 1; j++) {
                edits[i][j] = j;
            }
            edits[i][0] = i;
        }
        for (int i = 1; i < str2.length() + 1; i++) {
            for (int j = 1; j < str1.length() + 1; j++) {
                if (str2.charAt(i - 1) == str1.charAt(j - 1)) {
                    edits[i][j] = edits[i - 1][j - 1];
                } else {
                    edits[i][j] =
                            1 + Math.min(edits[i - 1][j - 1], Math.min(edits[i - 1][j], edits[i-1][j-1]));
                }
            }
        }
        return edits[str2.length()][str1.length()];
    }
}

Optimal:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
class Program {
    // O(nm) time | O(min(n, m)) space
    public static int levenshteinDistance(String str1, String str2) {
        String small = str1.length() < str2.length() ? str1 : str2;
        String big = str1.length() >= str2.length() ? str1 : str2;
        int[] evenEdits = new int[small.length() + 1];
        int[] oddEdits = new int[small.length() + 1];
        for (int j = 0; j < small.length() + 1; j++) {
            evenEdits[j] = j;
        }
        int[] currentEdits;
        int[] previousEdits;
        for (int i = 1; i < big.length() + 1; i++) {
            if (i % 2 == 1) {
                currentEdits = oddEdits;
                previousEdits = evenEdits;
            } else {
                currentEdits = evenEdits;
                previousEdits = oddEdits;
            }
            currentEdits[0] = i;
            for (int j = 1; j < small.length() + 1; j++) {
                if (big.charAt(i - 1) == small.charAt(j - 1)) {
                    currentEdits[j] = previousEdits[j - 1];
                } else {
                    currentEdits[j] = 1 + Math.min(previousEdits[j - 1],
                            Math.min(previousEdits[j], currentEdits[j-1]));
                }
            }
        }
        return big.length() % 2 == 0 ? evenEdits[small.length()] : oddEdits[small.length()];
    }
}
Your Content Goes Here

Problem:

Given an array , return boolean if it has a single cycle: number of forward steps are based on value in array, finally re-arrive to starting index by visiting all indices just once.

Leetcode:

457. Circular Array Loop

Solution: While loop

Extra space: use another array (initial vaule=0) to record number of visit, if any vaule >1, return false

No extra space:
Edge cases:

  1. when we are back to starting index and total number of visited index <N, N is the length of the array, return false
  2. when total number of visited =N, and we are not back to starting index, return false

JavaScript:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
// O(n) time | O(1) space - where n is the length of the input array 
function hasSingleCycle(array) {
    let numElementsVisited = 0;
    let currentIdx = 0;
    while (numElementsVisited < array.length) {
        if (numElementsVisited > 0 && currentIdx === 0) return false;
        numElementsVisited++;
        currentIdx = getNextIdx(currentIdx, array);
    }
    return currentIdx === 0;
}

function getNextIdx(currentIdx, array) {
    const jump = array[currentIdx];
    const nextIdx = (currentIdx + jump) % array.length;
    return nextIdx >= 0 ? nextIdx : nextIdx + array.length;
}

Java Code:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
class Program {
    // O(n) time | O(1) space - where n is the length of the input array 
    public static boolean hasSingleCycle(int[] array) {
        int numElementsVisited = 0;
        int currentIdx = 0;
        while (numElementsVisited < array.length) {
            if (numElementsVisited > 0 && currentIdx == 0) return false;
            numElementsVisited++;
            currentIdx = getNextIdx(currentIdx, array);
        }
        return currentIdx == 0;
    }

    public static int getNextIdx(int currentIdx, int[] array) {
        int jump = array[currentIdx];
        int nextIdx = (currentIdx + jump) % array.length;
        return nextIdx >= 0 ? nextIdx : nextIdx + array.length;
    }
}

Problem:

Use BFS to traverse all node of  G (V,E), and put them into an array, then return the array.

Solution: Queue+While loop

Time complexity : O ( | V | + | E | )     ;   Space complexity: O ( | V | )


JavaScript:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
// O(n) time | O(1) space - where n is the length of the input array 
function hasSingleCycle(array) {
    let numElementsVisited = 0;
    let currentIdx = 0;
    while (numElementsVisited < array.length) {
        if (numElementsVisited > 0 && currentIdx === 0) return false;
        numElementsVisited++;
        currentIdx = getNextIdx(currentIdx, array);
    }
    return currentIdx === 0;
}

function getNextIdx(currentIdx, array) {
    const jump = array[currentIdx];
    const nextIdx = (currentIdx + jump) % array.length;
    return nextIdx >= 0 ? nextIdx : nextIdx + array.length;
}

Java Code :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
class Program {
    static class Node {
        String name;
        List<Node> children = new ArrayList<Node>();

        public Node(String name) {
            this.name = name;
        }

        // O(v + e) time | O(v) space
        public List<String> breadthFirstSearch(List<String> array) {
            Queue<Node> queue = new LinkedList<Node>();
            queue.add(this);
            while (!queue.isEmpty()) {
                Node current = queue.poll();
                array.add(current.name);
                queue.addAll(current.children);
            }
            return array;
        }

        public Node addChild(String name) {
            Node child = new Node(name);
            children.add(child);
            return this;
        }
    }
}

Problem:

Given an m x n 2d grid map of '1's (river) and '0's (land), return the number of islands. Return an array, each value =  length of  a river.

An island is surrounded by water and is formed by connecting adjacent lands horizontally or vertically. You may assume all four edges of the grid are all surrounded by water.

Leetcode: 200. Number of Islands

Solution:

Traverse matrix

if matrix [ x ] [ y ]=1, apply BFS or DFS to find length of this river

push length into result array, then mark them as visited… Next, continue traverse matrix

Finally, return the result array.

JavaScript:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
// O(wh) time | O(wh) space
function riverSizes(matrix) {
    const sizes = [];
    const visited = matrix.map(row => row.map(value => false));
    for (let i = 0; i < matrix.length; i++) {
        for (let j = 0; j < matrix[i].length; j++) {
            if (visited[i][j]) continue;
            traverseNode(i, j, matrix, visited, sizes);
        }
    }
    return sizes;
}

function traverseNode(i, j, matrix, visited, sizes) {
    let currentRiverSize = 0;
    const nodesToExplore = [
        [i, j]
    ];
    while (nodesToExplore.length) {
        const currentNode = nodesToExplore.pop();
        i = currentNode[0];
        j = currentNode[1];
        if (visited[i][j]) continue;
        visited[i][j] = true;
        if (matrix[i][j] === 0) continue;
        currentRiverSize++;
        const unvisitedNeighbors = getUnvisitedNeighbors(i, j, matrix, visited);
        for (const neighbor of unvisitedNeighbors) {
            nodesToExplore.push(neighbor);
        }
    }
    if (currentRiverSize > 0) sizes.push(currentRiverSize);
}

function getUnvisitedNeighbors(i, j, matrix, visited) {
    const unvisitedNeighbors = [];
    if (i > 0 && !visited[i - 1][j]) unvisitedNeighbors.push([i - 1, j]);
    if (i < matrix.length - 1 && !visited[i + 1][j]) unvisitedNeighbors.push([i + 1, j]);
    if (j > 0 && !visited[i][j - 1]) unvisitedNeighbors.push([i, j - 1]);
    if (j < matrix[0].length - 1 && !visited[i][j + 1]) unvisitedNeighbors.push([i, j + 1]);
    return unvisitedNeighbors;
}

Java Code:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
class Program {
    // O(wh) time | O(wh) space
    public static List<Integer> riverSizes(int[][] matrix) {
        List<Integer> sizes = new ArrayList<Integer>();
        boolean[][] visited = new boolean[matrix.length][matrix[0].length];
        for (int i = 0; i < matrix.length; i++) {
            for (int j = 0; j < matrix[0].length; j++) {
                if (visited[i][j]) {
                    continue;
                }
                traverseNode(i, j, matrix, visited, sizes);
            }
        }
        return sizes;
    }

    public static void traverseNode(
            int i, int j, int[][] matrix, boolean[][] visited, List<Integer> sizes) {
        int currentRiverSize = 0;
        List<Integer[]> nodesToExplore = new ArrayList<Integer[]>();
        nodesToExplore.add(new Integer[]{i, j});
        while (!nodesToExplore.isEmpty()) {
            Integer[] currentNode = nodesToExplore.get(nodesToExplore.size() - 1);
            nodesToExplore.remove(nodesToExplore.size() - 1);
            i = currentNode[0];
            j = currentNode[1];
            if (visited[i][j]) {
                continue;
            }
            visited[i][j] = true;
            if (matrix[i][j] == 0) {
                continue;
            }
            currentRiverSize++;
            List<Integer[]> unvisitedNeighbors = 
                    getUnvisitedNeighbors(i, j, matrix, visited);
            for (Integer[] neighbor : unvisitedNeighbors) {
                nodesToExplore.add(neighbor);
            }
        }
        if (currentRiverSize > 0) {
            sizes.add(currentRiverSize);
        }
    }

    public static List<Integer[]> getUnvisitedNeighbors(int i, int j, int[][] matrix, boolean[][] visited) {
        List<Integer[]> unvisitedNeighbors = new ArrayList<Integer[]>();
        if (i > 0 && !visited[i - 1][j]) {
            unvisitedNeighbors.add(new Integer[]{i - 1, j});
        }
        if (i < matrix.length - 1 && !visited[i + 1][j]) {
            unvisitedNeighbors.add(new Integer[]{i + 1, j});
        }
        if (j > 0 && !visited[i][j - 1]) {
            unvisitedNeighbors.add(new Integer[]{i, j - 1});
        }
        if (j < matrix[0].length - 1 && !visited[i][j + 1]) {
            unvisitedNeighbors.add(new Integer[]{i, j + 1});
        }
        return unvisitedNeighbors;
    }
}

Problem:

Given three Nodes: top_Ancestor, descendant_One, descendant_Two. find and return the youngest common ancestor of One and Two.

Leetcode:
235. Lowest Common Ancestor of a Binary Search Tree
236. Lowest Common Ancestor of a Binary Tree

Solution: Time: O( D )  ||  Space: O( 1 )

D=depth of lowest node of One and Two

Bring two nodes to the same level ,

then go up step by step using while loop

return if go up step are the same.

  • find the depth of two nodes a, b, steps to same level= |a-b|

JavaScript:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
class AncestralTree {
    constructor(name) {
        this.name = name;
        this.ancestor = null;
    }
}
// O(d) time | O(1) space - where d is the depth (height) of the ancestral tree 
function getYoungestCommonAncestor(topAncestor, descendantOne, descendantTwo) {
    const depthOne = getDescendantDepth(descendantOne, topAncestor);
    const depthTwo = getDescendantDepth(descendantTwo, topAncestor);
    if (depthOne > depthTwo) {
        return backtrackAncestralTree(descendantOne, descendantTwo, depthOne - depthTwo);
    } else {
        return backtrackAncestralTree(descendantTwo, descendantOne, depthTwo - depthOne);
    }
}

function getDescendantDepth(descendant, topAncestor) {
    let depth = 0;
    while (descendant !== topAncestor) {
        depth++;
        descendant = descendant.ancestor;
    }
    return depth;
}

function backtrackAncestralTree(lowerDescendant, higherDescendant, diff) {
    while (diff > 0) {
        lowerDescendant = lowerDescendant.ancestor;
        diff--;
    }
    while (lowerDescendant !== higherDescendant) {
        lowerDescendant = lowerDescendant.ancestor;
        higherDescendant = higherDescendant.ancestor;
    }
    return lowerDescendant;
}

exports.AncestralTree = AncestralTree;
exports.getYoungestCommonAncestor = getYoungestCommonAncestor;

Java Code:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
class Program {
    // O(d) time | O(1) space - where d is the depth (height) of the ancestral tree
    public static AncestralTree getYoungestCommonAncestor(
            AncestralTree topAncestor,
            AncestralTree descendantOne,
            AncestralTree descendantTwo)
    {
        int depthOne = getDescendantDepth(descendantOne, topAncestor);
        int depthTwo = getDescendantDepth(descendantTwo, topAncestor);

        if (depthOne > depthTwo) {
            return backtrackAncestralTree(
                    descendantOne, descendantTwo, depthOne - depthTwo);
        } else {
            return backtrackAncestralTree(
                    descendantTwo, descendantOne, depthTwo - depthTwo);
        }
    }

    public static int getDescendantDepth(AncestralTree descendant,
                                         AncestralTree topAncestor) {
        int depth = 0;
        while (descendant != topAncestor) {
            depth++;
            descendant = descendant.ancestor;
        }
        return depth;
    }

    public static AncestralTree backtrackAncestralTree(
            AncestralTree lowerDescendant,
            AncestralTree higherDescendant,
            int diff)
    {
        //to same level
        while (diff > 0) {
            lowerDescendant = lowerDescendant.ancestor;
            diff--;
        }
        // go up to find same ancestor
        while (lowerDescendant != higherDescendant) {
            lowerDescendant = lowerDescendant.ancestor;
            higherDescendant = higherDescendant.ancestor;
        }
        return lowerDescendant;
    }

    //Ancestral Tree structure
    static class AncestralTree {
        public char name;
        public AncestralTree ancestor;

        AncestralTree(char name) {
            this.name = name;
            this.ancestor = null;
        }

        // This method is for testing only.
        void addAsAncestor(AncestralTree[] descendants) {
            for (AncestralTree descendant : descendants) {
                descendant.ancestor = this;
            }
        }
    }
}

Problem: Given head of Linked List, Remove Nth Node From End.

Solution: Two Pointers || Time: O(N) Space: O(1)

  1. let Slow Fast Pointer =head, let fast pointer move N steps, Now Fast Point is N nodes ahead of Slow Pointer.
  2. Continuing move both Pointers to traverse Linked List until Fast.Next=null, remove slow pointer node: slow.previous=slow.next.

Edge case: N=length of Linked List, when Fast move N node, Fast=null, return slow.next node.
JavaScript:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
class LinkedList {
    constructor(value) {
        this.value = value;
        this.next = null;
    }
} 

// O(n) time | O(1) space
function removeKthNodeFromEnd(head, k) {
    let counter = 1;
    let first = head;
    let second = head;
    while (counter <= k) {
        second = second.next;
        counter++;
    }
    if (second === null) {
        head.value = head.next.value;
        head.next = head.next.next;
        return;
    }
    while (second.next !== null) {
        second = second.next;
        first = first.next;
    }
    first.next = first.next.next;
}
exports.LinkedList = LinkedList;
exports.removeKthNodeFromEnd = removeKthNodeFromEnd;

Java Code:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
class Program {
    // O(n) time | O(1) space
    public static void removeKthNodeFromEnd(LinkedList head, int k) {
        int counter = 1;
        LinkedList first = head;
        LinkedList second = head;
        while (counter <= k) {
            second = second.next;
            counter++;
        }
        if (second == null) {
            head.value = head.next.value;
            head.next = head.next.next;
            return;
        }
        while (second.next != null) {
            second = second.next;
            first = first.next;
        }
        first.next = first.next.next;
    }

    static class LinkedList {
        int value;
        LinkedList next = null;

        public LinkedList(int value) {
            this.value = value;
        }
    }
}

Problem: Given an array with unique integers, return all possible array.

Solution: Swap in Array (Optimal), Recursion.

Swap Code:

JavaScript:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
// Upper Bound: O(n^2*n!) time | O(n*n!) space
// Roughly: O(n*n!) time | O(n*n!) space
function getPermutations(array) {
    const permutations = [];
    permutationsHelper(array, [], permutations);
    return permutations;
}

function permutationsHelper(array, currentPermutation, permutations) {
    if (!array.length && currentPermutation.length) {
        permutations.push(currentPermutation);
    } else {
        for (let i = 0; i < array.length; i++) {
            const newArray = array.slice(0, i).concat(array.slice(i + 1));
            const newPermutation = currentPermutation.concat([array[i]]);
            permutationsHelper(newArray, newPermutation, permutations);
        }
    }
}
exports.getPermutations = getPermutations;

Java:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
class Program {
    // O(n*n!) time | O(n*n!) space
    public static List<List<Integer>> getPermutations(List<Integer> array) {
        List<List<Integer>> permutations = new ArrayList<List<Integer>>();
        getPermutations(0, array, permutations);
        return permutations;
    }

    public static void getPermutations(
            int i,
            List<Integer> array,
            List<List<Integer>> permutations) {

        if (i == array.size() - 1) {
            permutations.add(new ArrayList<Integer>(array));
        } else {
            for (int j = i; j < array.size(); j++) {
                swap(array, i, j);
                //go next position
                getPermutations(i + 1, array, permutations);
                //undo swap
                swap(array, i, j);
            }
        }

    }

    public static void swap(List<Integer> array, int i, int j) {
        Integer tmp = array.get(i);
        array.set(i, array.get(j));
        array.set(j, tmp);
    }
}

Recursion Code:
JavaScript:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// O(n*n!) time | O(n*n!) space
function getPermutations(array) {
    const permutations = [];
    permutationsHelper(0, array, permutations);
    return permutations;
}

function permutationsHelper(i, array, permutations) {
    if (i === array.length - 1) {
        permutations.push(array.slice());
    } else {
        for (let j = i; j < array.length; j++) {
            swap(i, j, array);
            permutationsHelper(i + 1, array, permutations);
            swap(i, j, array);
        }
    }
}

function swap(i, j, array) {
    const temp = array[i];
    array[i] = array[j];
    array[j] = temp;
}
exports.getPermutations = getPermutations;

Java:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
class Program {
    // Upper Bound: O(n^2*n!) time | O(n*n!) space
    // Roughly: O(n*n!) time | O(n*n!) space
    public static List<List<Integer>> getPermutations(List<Integer> array) {
        List<List<Integer>> permutations = new ArrayList<List<Integer>>();
        getPermutations(array, new ArrayList<Integer>(), permutations);
        return permutations;
    }

    public static void getPermutations(
            List<Integer> array,
            List<Integer> currentPermutation,
            List<List<Integer>> permutations) {

        if (array.size() == 0 && currentPermutation.size() > 0) {
            permutations.add(currentPermutation);
        } else {
            for (int i = 0; i < array.size(); i++) {
                List<Integer> newArray = new ArrayList<Integer>(array);
                newArray.remove(i);
                List<Integer> newPermutation = new ArrayList<Integer>(currentPermutation);
                newPermutation.add(array.get(i));
                getPermutations(newArray, newPermutation, permutations);
            }
        }
    }
}

Problem: Given an array, return the Powerset. it’s defined as the set of all sub of another set.

Solution: Iteration or Recursion

Iteration: Time,Space=O(2^n*n)

  1. []
  2. add 1, {[],[1]}
  3. add 2, {[],[1], [2], [1,2]}
  4. add 3, {[],[1], [2], [1,2], [3],[1,3], [2,3], [1,2,3]}

JavaScript:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
// O(n*2^n) time | O(n*2^n) space
function powerset(array) {
    const subsets = [[]];
    for (const ele of array) {
        const length = subsets.length;
        for (let i = 0; i < length; i++) {
            const currentSubset = subsets[i];
            subsets.push(currentSubset.concat(ele));
        }
    }
    return subsets;
}
exports.powerset = powerset;

Java Code:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
class Program {
    // O(n*2^n) time | O(n*2^n) space
    public static List<List<Integer>> powerset(List<Integer> array) {
        List<List<Integer>> subsets = new ArrayList<List<Integer>>();
        subsets.add(new ArrayList<Integer>());
        for (Integer ele : array) {
            int length = subsets.size();
            for (int i = 0; i < length; i++) {
                List<Integer> currentSubset = new ArrayList<Integer>(subsets.get(i));
                currentSubset.add(ele);
                subsets.add(currentSubset);
            }
        }
        return subsets;
    }
}

Problem: Given a sorted Matrix and an Integer, return the index of the Integer in that Matrix.

Solution: While lopp

  1. Martix[row][col]
    starts from Top Left
  2. if(Martix[row][col] >targer)  col--;
  3. if(Martix[row][col] <targer)  row++;
  4. else return Martix[row][col]

JavaScript:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
// O(n + m) time | O(1) space
function searchInSortedMatrix(matrix, target) {
    let row = 0;
    let col = matrix[0].length - 1;
    while (row < matrix.length && col >= 0) {
        if (matrix[row][col] > target) {
            col--;
        } else if (matrix[row][col] < target) {
            row++;
        } else {
            return [row, col];
        }
    }
    return [-1, -1];
}
exports.searchInSortedMatrix = searchInSortedMatrix;

Java:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
class Program {
    // O(n) time | O(1) space
    public static int[] searchInSortedMatrix(int[][] matrix, int target) {
        int row = 0;
        int col = matrix[0].length - 1;
        while (row < matrix.length && col >= 0) {
            // go left, down or return
            if (matrix[row][col] > target) {
                col--;
            } else if (matrix[row][col] < target) {
                row++;
            } else {
                return new int[]{row, col};
            }
        }
        return new int[]{-1, -1};
    }

}

Problem: Define Min Max Stack Data Structure with peek(), pop(), push(), getMin(), getMax().

Solution:

  1. Use List<Map<String, Integer>> minMaxStack to store history min and max value.
  2. Use List stack to store Stack Values


JavaScript:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
class MinMaxStack {
    constructor() {
        this.minMaxStack = [];
        this.stack = [];
    }
    // O(1) time | O(1) space   
    peek() {
        return this.stack[this.stack.length - 1];
    }
    // O(1) time | O(1) space
    pop() {
        this.minMaxStack.pop();
        return this.stack.pop();
    }
    // O(1) time | O(1) space   
    push(number) {
        const newMinMax = {
            min: number,
            max: number
        };
        if (this.minMaxStack.length) {
            const lastMinMax = this.minMaxStack[this.minMaxStack.length - 1];
            newMinMax.min = Math.min(lastMinMax.min, number);
            newMinMax.max = Math.max(lastMinMax.max, number);
        }
        this.minMaxStack.push(newMinMax);
        this.stack.push(number);
    }
    // O(1) time | O(1) space   
    getMin() {
        return this.minMaxStack[this.minMaxStack.length - 1].min;
    }
    // O(1) time | O(1) space
    getMax() {
        return this.minMaxStack[this.minMaxStack.length - 1].max;
    }
}

Java Code:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
class MinMaxStack {
    List<Map<String, Integer>> minMaxStack = new ArrayList<Map<String, Integer>>();
    List<Integer> stack = new ArrayList<Integer>();

    // O(1) time | O(1) space
    public int peek() {
        return stack.get(stack.size() - 1);
    }

    // O(1) time | O(1) space
    public int pop() {
        minMaxStack.remove(minMaxStack.size() - 1);
        return stack.remove(stack.size() - 1);
    }

    // O(1) time | O(1) space
    public void push(int number) {
        Map<String, Integer> newMinMax = new HashMap<String, Integer>();
        newMinMax.put("min", number);
        newMinMax.put("max", number);
        if (minMaxStack.size() > 0) {
            Map<String, Integer> lastMinMax =
                    new HashMap<String, Integer>(minMaxStack.get(minMaxStack.size() - 1));
            newMinMax.replace("min", Math.min(lastMinMax.get("min"), number));
            newMinMax.replace("max", Math.max(lastMinMax.get("max"), number));
        }
        minMaxStack.add(newMinMax);
        stack.add(number);
    }

    // O(1) time | O(1) space
    public int getMin() {
        return minMaxStack.get(minMaxStack.size() - 1).get("min");
    }

    // O(1) time | O(1) space
    public int getMax() {
        return minMaxStack.get(minMaxStack.size() - 1).get("max");
    }
}

Problem: Given a String, return  the Longest Palindromic Substring.

A palindrome [pælin’drɔmik] is defined as a string that’s written the same forward as backward.

Solution: Iteration || Time=O(n^2)  Space=O(1)

Traverse the String to check each center and expand from them.

  1. At index i, if (Str[i-1]==Str[i+1]) odd
  2. else if(Str[i]==Str[i-1]) even

Palindrome can be either if even length or odd length.


JavaScript:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
// O(n^2) time | O(1) space
function longestPalindromicSubstring(string) {
    let currentLongest = [0, 1];
    for (let i = 1; i < string.length; i++) {
        const odd = getLongestPalindromeFrom(string, i - 1, i + 1);
        const even = getLongestPalindromeFrom(string, i - 1, i);
        const longest = odd[1] - odd[0] > even[1] - even[0] ? odd : even;
        currentLongest = currentLongest[1] - currentLongest[0] > longest[1] - longest[0] ? currentLongest : longest;
    }
    return string.slice(currentLongest[0], currentLongest[1]);
}

function getLongestPalindromeFrom(string, leftIdx, rightIdx) {
    while (leftIdx >= 0 && rightIdx < string.length) {
        if (string[leftIdx] !== string[rightIdx]) break;
        leftIdx--;
        rightIdx++;
    }
    return [leftIdx + 1, rightIdx];
}
exports.longestPalindromicSubstring = longestPalindromicSubstring;

JavaScript:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
// O(w * n * log(n)) time | O(wn) space - where w is the number of words and n is 
function groupAnagrams(words) {
    const anagrams = {};
    for (const word of words) {
        const sortedWord = word.split('').sort().join('');
        if (sortedWord in anagrams) {
            anagrams[sortedWord].push(word);
        } else {
            anagrams[sortedWord] = [word];
        }
    }
    return Object.values(anagrams);
}
exports.groupAnagrams = groupAnagrams;

Java Code:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
class Program {
    // O(n^2) time | O(1) space
    public static String longestPalindromicSubstring(String str) {
        int[] currentLongest = {0, 1};
        for (int i = 1; i < str.length(); i++) {
            int[] odd = getLongestPalindromeFrom(str, i - 1, i + 1);
            int[] even = getLongestPalindromeFrom(str, i - 1, i);
            int[] longest = odd[1] - odd[0] > even[1] - even[0] ? odd : even;
            currentLongest =
                    currentLongest[1] - currentLongest[0] >
                            longest[1] - longest[0] ? currentLongest : longest;
        }
        return str.substring(currentLongest[0], currentLongest[1]);
    }

    public static int[] getLongestPalindromeFrom(String str, int leftIdx, int rightIdx) {
        while (leftIdx >= 0 && rightIdx < str.length()) {
            if (str.charAt(leftIdx) != str.charAt(rightIdx)) {
                break;
            }
            leftIdx--;
            rightIdx++;
        }
        return new int[]{leftIdx + 1, rightIdx};
    }
}

Problem:

Given an array of strings strs, group the anagrams together. You can return the answer in any order.

An Anagram is a word or phrase formed by rearranging the letters of a different word or phrase, typically using all the original letters exactly once.

Leetcode: 49. Group Anagrams

Solution: check out comments in Code

Java Code:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
class Program {
    // O(w * n * log(n)) time | O(wn) space - where w is the number of words and n 
    // the longest word
    public static List<List<String>> groupAnagrams(List<String> words) {
        // <String,List of Index>
        Map<String, List<String>> anagrams = new HashMap<String, List<String>>();
        //Sort each string then compare to decide add the string or append index in Map.
        for (String word : words) {
            char[] charArray = word.toCharArray();
            Arrays.sort(charArray);
            String sortedWord = new String(charArray);
            if (anagrams.containsKey(sortedWord)) {
                anagrams.get(sortedWord).add(word);
            } else {
                anagrams.put(sortedWord, new ArrayList<String>(Arrays.asList(word)));
            }
        }
        List<List<String>> output = new ArrayList<List<String>>();
        //push into result list
        for (Map.Entry<String, List<String>> entry : anagrams.entrySet()) {
            output.add(entry.getValue());
        }
        return output;
    }
}

 

Problem : Construct Suffix Trie Tree in order to recognize if given string a is suffix of string b

Asterisk means end of the string.


JavaScript:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
class SuffixTrie {
    constructor(string) {
        this.root = {};
        this.endSymbol = '*';
        this.populateSuffixTrieFrom(string);
    }
    // O(n^2) time | O(n^2) space   
    populateSuffixTrieFrom(string) {
        for (let i = 0; i < string.length; i++) {
            this.insertSubstringStartingAt(i, string);
        }
    }
    insertSubstringStartingAt(i, string) {
        let node = this.root;
        for (let j = i; j < string.length; j++) {
            const letter = string[j];
            if (!(letter in node)) node[letter] = {};
            node = node[letter];
        }
        node[this.endSymbol] = true;
    }
    // O(m) time | O(1) space   
    contains(string) {
        let node = this.root;
        for (const letter of string) {
            if (!(letter in node)) return false;
            node = node[letter];
        }
        return this.endSymbol in node;
    }
}

Java Code:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
class TrieNode {
    Map<Character, TrieNode> children = new HashMap<Character, TrieNode>();

    static class SuffixTrie {
        TrieNode root = new TrieNode();
        char endSymbol = '*';

        public SuffixTrie(String str) {
            populateSuffixTrieFrom(str);
        }


        // Creation: O(n^2) time | O(n^2) space
        public void populateSuffixTrieFrom(String str) {
            //traverse str to construct suffix Trie
            for (int i = 0; i < str.length(); i++) {
                insertSubstringStartingAt(i, str);
            }
        }

        public void insertSubstringStartingAt(int i, String str) {
            TrieNode node = root;
            //construct from index i
            for (int j = i; j < str.length(); j++) {
                char letter = str.charAt(j);
                if (!node.children.containsKey(letter)) {
                    TrieNode newNode = new TrieNode();
                    node.children.put(letter, newNode);
                }
                node = node.children.get(letter);
            }
            node.children.put(endSymbol, null);
        }

        // Search: O(m) time | O(1) space
        public boolean contains(String str) {
            TrieNode node = root;
            for (int i = 0; i < str.length(); i++) {
                char letter = str.charAt(i);
                if (!node.children.containsKey(letter)) {
                    return false;
                }
                node = node.children.get(letter);
            }
            return node.children.containsKey(endSymbol);
        }
    }
}