Press "Enter" to skip to content

Posts published in “Algorithms”

LeetCode 153. Find Minimum in Rotated Sorted Array (javascript)


Suppose an array of length n sorted in ascending order is rotated between 1 and n times. For example, the array nums = [0,1,2,4,5,6,7] might become:

  • [4,5,6,7,0,1,2] if it was rotated 4 times.
  • [0,1,2,4,5,6,7] if it was rotated 7 times.

Notice that rotating an array [a[0], a[1], a[2], ..., a[n-1]] 1 time results in the array [a[n-1], a[0], a[1], a[2], ..., a[n-2]].

Given the sorted rotated array nums of unique elements, return the minimum element of this array.

Example 1:

Input: nums = [3,4,5,1,2]
Output: 1
Explanation: The original array was [1,2,3,4,5] rotated 3 times.

Example 2:

Input: nums = [4,5,6,7,0,1,2]
Output: 0
Explanation: The original array was [0,1,2,4,5,6,7] and it was rotated 4 times.

Example 3:

Input: nums = [11,13,15,17]
Output: 11
Explanation: The original array was [11,13,15,17] and it was rotated 4 times. 

Constraints:

  • n == nums.length
  • 1 <= n <= 5000
  • -5000 <= nums[i] <= 5000
  • All the integers of nums are unique.
  • nums is sorted and rotated between 1 and n times.

Idea:

Use Binary Search Template

  • Time Complexity: O(logN)
  • Space Complexity: O(1)

Solution:

/**
 * @param {number[]} nums
 * @return {number}
 */
var findMin = function(nums) {
    // if only have one number
    if (nums.length === 1) return nums[0];
    
    let l = 0;
    let r = nums.length;
    // if this array is sorted
    if (nums[0] < nums[r - 1]) return nums[0];
    
    while (l < r) {
        let mid = l + Math.floor((r - l) / 2);
        
        // if previous element is greater than next element,
        // next element is the smallest
        if (nums[mid] > nums[mid + 1]) 
            return nums[mid + 1];
        if (nums[mid - 1] > nums[mid]) 
            return nums[mid];
        
        // first half is sorted: min is on right side
        if (nums[mid] > nums[0]) 
            l = mid;
        else
            r = mid + 1;
    } 
    return -1;
};

Solution 2:

var findMin = function(nums) {
    return searchMin(nums, 0, nums.length - 1);
};

function searchMin(nums, l, r) {
    // exit recursion:
    // only one or two elements in the array
    if (l + 1 >= r)
        return Math.min(nums[l], nums[r]);
    // this array is sorted
    if (nums[l] < nums[r])
        return nums[l];
    
    let mid = l + Math.floor((r - l) / 2);
    return Math.min(searchMin(nums, l , mid), searchMin(nums, mid + 1, r));
}

LeetCode 112. Path Sum (javascript)

Given the root of a binary tree and an integer targetSum, return true if the tree has a root-to-leaf path such that adding up all the values along the path equals targetSum.

leaf is a node with no children.

Example 1:

Input: root = [5,4,8,11,null,13,4,7,2,null,null,null,1], targetSum = 22
Output: true

Example 2:

Input: root = [1,2,3], targetSum = 5
Output: false

Example 3:

Input: root = [1,2], targetSum = 0
Output: false

Constraints:

  • The number of nodes in the tree is in the range [0, 5000].
  • -1000 <= Node.val <= 1000
  • -1000 <= targetSum <= 1000

Solution: (Recursion)

  • Time complexity: O(n)
  • Space complexity: O(n)
/**
 * Definition for a binary tree node.
 * function TreeNode(val, left, right) {
 *     this.val = (val===undefined ? 0 : val)
 *     this.left = (left===undefined ? null : left)
 *     this.right = (right===undefined ? null : right)
 * }
 */
/**
 * @param {TreeNode} root
 * @param {number} targetSum
 * @return {boolean}
 */
var hasPathSum = function(root, targetSum) {
    if (root === null) return false;
    if (root.val === targetSum && root.left === null && root.right === null) return true;
    return hasPathSum(root.left, targetSum - root.val) ||
           hasPathSum(root.right, targetSum - root.val);
};

LeetCode 85. Maximal Rectangle (javascript)

Given a rows x cols binary matrix filled with 0‘s and 1‘s, find the largest rectangle containing only 1‘s and return its area.

Example 1:

Input: matrix = [["1","0","1","0","0"],["1","0","1","1","1"],["1","1","1","1","1"],["1","0","0","1","0"]]
Output: 6
Explanation: The maximal rectangle is shown in the above picture.

Example 2:

Input: matrix = []
Output: 0

Example 3:

Input: matrix = [["0"]]
Output: 0

Example 4:

Input: matrix = [["1"]]
Output: 1

Example 5:

Input: matrix = [["0","0"]]
Output: 0

Constraints:

  • rows == matrix.length
  • cols == matrix[i].length
  • 0 <= row, cols <= 200
  • matrix[i][j] is '0' or '1'.

Idea:

Dynamic Programing

  • Time complexity: O(mn)
  • Space complexity: O(mn)
dp[i][j] := max length of all 1s ends with col j at row i.
dp[i][j] = 0 if matrix[i][j] == "0"
dp[i][j] = dp[i][j-1] + 1 if matrix[i][j] == "1"

Then loop through matrix
Min Width(has "1"):= Math.min(width, dp[curRow][j]);
Min Height(has "1"):= curRow - i + 1;
MaxArea = Min Width * Min Height

Solution:

/**
 * @param {character[][]} matrix
 * @return {number}
 */
var maximalRectangle = function(matrix) {    
    let row = matrix.length;
    if (row === 0) return 0;
    let col = matrix[0].length;
    
    // dp[i][j] := max length of all 1s ends with col j at row i.
    // dp[i][j] = 0 if matrix[i][j] == "0"
    // dp[i][j] = dp[i][j-1] + 1 if matrix[i][j] == "1"
    let dp = Array.from(new Array(row), () => new Array(col));
    for (let i = 0; i < row; i++) {
        for (let j = 0; j < col; j++) {
            if (matrix[i][j] === "1") {
                dp[i][j] = j === 0 ? 1 : dp[i][j - 1] + 1;
            } else {
                dp[i][j] = 0;
            }
        }
    }
    
    let maxArea = 0;
    for (let i = 0; i < row; i++) {
        for (let j = 0; j < col; j++) {
            let width = Infinity;
            for (let curRow = i; curRow < row; curRow++) {
                width = Math.min(width, dp[curRow][j]);
                if (width === 0) break;
                let height = curRow - i + 1;
                maxArea = Math.max(maxArea, width * height);
            }
        }
    }
    return maxArea;
};

LeetCode 917. Reverse Only Letters (javascript)

Given a string S, return the “reversed” string where all characters that are not a letter stay in the same place, and all letters reverse their positions.

Example 1:

Input: "ab-cd"
Output: "dc-ba"

Example 2:

Input: "a-bC-dEf-ghIj"
Output: "j-Ih-gfE-dCba"

Example 3:

Input: "Test1ng-Leet=code-Q!"
Output: "Qedo1ct-eeLg=ntse-T!"

Note:

  1. S.length <= 100
  2. 33 <= S[i].ASCIIcode <= 122 
  3. S doesn’t contain \ or "

Idea:

Two pointers

Solution:

/**
 * @param {string} S
 * @return {string}
 */
var reverseOnlyLetters = function(S) {
    let l = 0;
    let r = S.length - 1;
    let arr = S.split('');
    
    while (l < r) {
        if (!isAlpha(arr[l])) l++;
        if (!isAlpha(arr[r])) r--;
        if (isAlpha(arr[l]) && isAlpha(arr[r])) {
            // swap
            [arr[l], arr[r]] = [arr[r], arr[l]];
            l++
            r--;
        }
    }
    return arr.join('');
};

var isAlpha = (c) => /[a-zA-Z]/.test(c);

LeetCode 35. Search Insert Position (javascript)

Given a sorted array of distinct integers and a target value, return the index if the target is found. If not, return the index where it would be if it were inserted in order.

Example 1:

Input: nums = [1,3,5,6], target = 5
Output: 2

Example 2:

Input: nums = [1,3,5,6], target = 2
Output: 1

Example 3:

Input: nums = [1,3,5,6], target = 7
Output: 4

Example 4:

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

Example 5:

Input: nums = [1], target = 0
Output: 0

Constraints:

  • 1 <= nums.length <= 104
  • -104 <= nums[i] <= 104
  • nums contains distinct values sorted in ascending order.
  • -104 <= target <= 104

Idea:

Use Binary Search

  • Time complexity: O(logn)
  • Space complexity: O(1)

Solution:

/**
 * @param {number[]} nums
 * @param {number} target
 * @return {number}
 */
var searchInsert = function(nums, target) {
    let l = 0;
    let r = nums.length;
    
    while (l < r) {
        let mid = l + Math.floor((r - l) / 2);
        if (nums[mid] === target) {
            return mid;
        } else if (nums[mid] > target) {
            r = mid;
        } else {
            l = mid + 1;
        }
    }
    return l;
};

LeetCode 17. Letter Combinations of a Phone Number (javascript)

Given a string containing digits from 2-9 inclusive, return all possible letter combinations that the number could represent. Return the answer in any order.

A mapping of digit to letters (just like on the telephone buttons) is given below. Note that 1 does not map to any letters.

Example 1:

Input: digits = "23"
Output: ["ad","ae","af","bd","be","bf","cd","ce","cf"]

Example 2:

Input: digits = ""
Output: []

Example 3:

Input: digits = "2"
Output: ["a","b","c"]

Constraints:

  • 0 <= digits.length <= 4
  • digits[i] is a digit in the range ['2', '9'].

Idea:

Use DFS template

Solution:

/**
 * @param {string} digits
 * @return {string[]}
 */
var letterCombinations = function(digits) {
    let res = [];
    if (digits.length === 0) return res;
    // you can use array or use hashmap
    const nums = [];
    nums[2] = ['a','b','c'];
    nums[3] = ['d','e','f'];
    nums[4] = ['g','h','i'];
    nums[5] = ['j','k','l'];
    nums[6] = ['m','n','o'];
    nums[7] = ['p','q','r','s'];
    nums[8] = ['t','u','v'];
    nums[9] = ['w','x','y','z'];
    dfs(res, 0, "", nums, digits);
    return res;
};

function dfs(res, start, cur, nums, digits) {
    // exit recursive conditon
    if (cur.length === digits.length) {
        res.push(cur);
        return;
    }
    // possible solution
    let possibleLetters = nums[digits[start]];                                                               
    for (let letter of possibleLetters) {
        // modify: add the letter to our current solution
        cur += letter;
        dfs(res, start + 1, cur, nums, digits);
        // recover: backtrack by removing the letter
        // before moving onto the next
        cur = cur.substring(0, cur.length - 1);
    }
}

LeetCode 133. Clone Graph (javascript)

Given a reference of a node in a connected undirected graph.

Return a deep copy (clone) of the graph.

Each node in the graph contains a val (int) and a list (List[Node]) of its neighbors.

class Node {
    public int val;
    public List<Node> neighbors;
}

Test case format:

For simplicity sake, each node’s value is the same as the node’s index (1-indexed). For example, the first node with val = 1, the second node with val = 2, and so on. The graph is represented in the test case using an adjacency list.

Adjacency list is a collection of unordered lists used to represent a finite graph. Each list describes the set of neighbors of a node in the graph.

The given node will always be the first node with val = 1. You must return the copy of the given node as a reference to the cloned graph.

Example 1:

Input: adjList = [[2,4],[1,3],[2,4],[1,3]]
Output: [[2,4],[1,3],[2,4],[1,3]]
Explanation: There are 4 nodes in the graph.
1st node (val = 1)'s neighbors are 2nd node (val = 2) and 4th node (val = 4).
2nd node (val = 2)'s neighbors are 1st node (val = 1) and 3rd node (val = 3).
3rd node (val = 3)'s neighbors are 2nd node (val = 2) and 4th node (val = 4).
4th node (val = 4)'s neighbors are 1st node (val = 1) and 3rd node (val = 3).

Example 2:

Input: adjList = [[]]
Output: [[]]
Explanation: Note that the input contains one empty list. The graph consists of only one node with val = 1 and it does not have any neighbors.

Example 3:

Input: adjList = []
Output: []
Explanation: This an empty graph, it does not have any nodes.

Example 4:

Input: adjList = [[2],[1]]
Output: [[2],[1]]

Constraints:

  • 1 <= Node.val <= 100
  • Node.val is unique for each node.
  • Number of Nodes will not exceed 100.
  • There is no repeated edges and no self-loops in the graph.
  • The Graph is connected and all nodes can be visited starting from the given node.

Idea:

BFS Queue + HashMap +

我们使用 BFS 来遍历图,使用队列 queue 进行辅助,一个 HashMap 来建立原图结点和克隆结点之间的映射。先克隆当前结点,然后建立映射,并加入 queue 中,进行 while 循环。在循环中,取出队首结点,遍历其所有 neighbor 结点,若不在 HashMap 中,我们根据 neigbor 结点值克隆一个新 neighbor 结点,建立映射,并且排入 queue 中。然后将 neighbor 结点在 HashMap 中的映射结点加入到克隆结点的 neighbors 数组中即可,参见代码如下:

  • Time complexity: O(V+E) 点+边
  • Space complexity: O(V+E)

Solution 1:

/**
 * // Definition for a Node.
 * function Node(val, neighbors) {
 *    this.val = val === undefined ? 0 : val;
 *    this.neighbors = neighbors === undefined ? [] : neighbors;
 * };
 */
/**
 * @param {Node} node
 * @return {Node}
 */
var cloneGraph = function(node) {
    if (node === null) return null;
    let map = new Map();
    map.set(node, new Node(node.val));
    let q = []; // queue
    q.push(node);
    while (q.length !== 0) {
        let cur = q.shift();
        for (let n of cur.neighbors) {
            if (!map.has(n)) {
                map.set(n, new Node(n.val));
                q.push(n);
            }
            map.get(cur).neighbors.push(map.get(n));
        }
    }
    return map.get(node);
};

Solution 2:

var cloneGraph = function(node) {
    if (node === null) return null;
    let visited = new Map();
    let map = new Map();
    let q = []; // queue
    q.push(node);
    while (q.length !== 0) {
        let cur = q.shift();
        if (visited.has(cur)) continue;
        visited.set(cur, true);
        if (!map.has(cur)) map.set(cur, new Node(cur.val));
        let temp = map.get(cur);
        for (let n of cur.neighbors) {
            if (!map.has(n)) map.set(n, new Node(n.val));
            q.push(n);
            temp.neighbors.push(map.get(n));
        }
    }
    return map.get(node);
};

LeetCode 700. Search in a Binary Search Tree (javascript)

You are given the root of a binary search tree (BST) and an integer val.

Find the node in the BST that the node’s value equals val and return the subtree rooted with that node. If such a node does not exist, return null.

Example 1:

Input: root = [4,2,7,1,3], val = 2
Output: [2,1,3]

Example 2:

Input: root = [4,2,7,1,3], val = 5
Output: []

Constraints:

  • The number of nodes in the tree is in the range [1, 5000].
  • 1 <= Node.val <= 107
  • root is a binary search tree.
  • 1 <= val <= 107

Solution:

/**
 * Definition for a binary tree node.
 * function TreeNode(val, left, right) {
 *     this.val = (val===undefined ? 0 : val)
 *     this.left = (left===undefined ? null : left)
 *     this.right = (right===undefined ? null : right)
 * }
 */
/**
 * @param {TreeNode} root
 * @param {number} val
 * @return {TreeNode}
 */
var searchBST = function(root, val) {
    if (root === null) return null
    if (root.val === val)
        return root;
    else if (val < root.val)
        return searchBST(root.left, val);
    else
        return searchBST(root.right, val);
};

LeetCode 24. Swap Nodes in Pairs (javascript)

Given a linked list, swap every two adjacent nodes and return its head.

Example 1:

Input: head = [1,2,3,4]
Output: [2,1,4,3]

Example 2:

Input: head = []
Output: []

Example 3:

Input: head = [1]
Output: [1]

Constraints:

  • The number of nodes in the list is in the range [0, 100].
  • 0 <= Node.val <= 100

Solution:

/**
 * Definition for singly-linked list.
 * function ListNode(val, next) {
 *     this.val = (val===undefined ? 0 : val)
 *     this.next = (next===undefined ? null : next)
 * }
 */
/**
 * @param {ListNode} head
 * @return {ListNode}
 */
var swapPairs = function(head) {
    if (head === null) return null;
    if (head.next === null) return head;
    let dummy = head;
    while (head !== null && head.next !== null) {
        swap(head);
        if (head.next !== null)
            head = head.next.next;
    }
    return dummy;
};

function swap(head) {
    [head.val, head.next.val] = [head.next.val, head.val];
    return head;
}

LeetCode 169. Majority Element (javascript)

Given an array nums of size n, return the majority element.

The majority element is the element that appears more than ⌊n / 2⌋ times. You may assume that the majority element always exists in the array.

Example 1:

Input: nums = [3,2,3]
Output: 3

Example 2:

Input: nums = [2,2,1,1,1,2,2]
Output: 2

Constraints:

  • n == nums.length
  • 1 <= n <= 5 * 104
  • -231 <= nums[i] <= 231 - 1

Solution 1: (Hash Table)

  • Time Complexity : O(n)
  • Space Complexity : O(n)
/**
 * @param {number[]} nums
 * @return {number}
 */
var majorityElement = function(nums) {
    let map = new Map();
    for (let num of nums) {
        map.set(num, (map.has(num) ? map.get(num) : 0)  + 1);
        if (map.get(num) > nums.length / 2) return num;
    }
    return -1;
};

Solution 2: (Sorting)

  • Time Complexity : O(n)
  • Space Complexity : O(1)
var majorityElement = function(nums) {
    nums.sort();
    return nums[Math.floor(nums.length / 2)];
};

Solution 3: (Divide and conquer)

  • Time Complexity : O(nlogn)
  • Space Complexity : O(logn)
var majorityElement = function(nums) {
    return majority(nums, 0, nums.length - 1);
};

function majority(nums, l, r) {
    if (l === r) return nums[l];
    const mid = l + Math.floor((r - l) / 2);
    const left = majority(nums, l , mid);
    const right = majority(nums, mid + 1, r);
    if (left === right) return left;
    return nums.slice(l, r + 1).filter(x => x === left).length >
           nums.slice(l, r + 1).filter(x => x === right).length
           ? left : right;
}