Triangle

Given a triangle, find the minimum path sum from top to bottom. Each step you may move to adjacent numbers on the row below.

Example

For example, given the following triangle
[
[2],
[3,4],
[6,5,7],
[4,1,8,3]
]
The minimum path sum from top to bottom is 11 (i.e., 2 + 3 + 5 + 1 = 11).

Note

Bonus point if you are able to do this using only O(n) extra space, where n is the total number of rows in the triangle.

Version 1. Up-Bottom

想法直白 但是做起来麻烦 要考虑很多边界条件 不推荐

//f[i][j] = Math.min(f[i-1][j-1], f[i-1][j])+grid[i][j]
public int minimumTotal(ArrayList<ArrayList<Integer>> triangle) {
    //O(n^2) space
    //f[i][j] = Math.min(f[i-1][j-1], f[i-1][j])+grid[i][j]
    if (triangle == null || triangle.size() == 0) {
        return 0;
    }
    int size = triangle.size();
    int[][] resultMap = new int[size][size];
    resultMap[0][0] = triangle.get(0).get(0);
    for (int i = 1; i < size; i++) {
        ArrayList<Integer> curr = triangle.get(i);
        for (int j = 0; j < curr.size(); j++) {
            if (j == 0) {
                resultMap[i][j] = resultMap[i - 1][j] + curr.get(j);
            } else {
                if (j < triangle.get(i - 1).size()) {
                    resultMap[i][j] = Math.min(resultMap[i - 1][j - 1], resultMap[i - 1][j]) + curr.get(j);
                } else {
                    resultMap[i][j] = resultMap[i - 1][j - 1] + curr.get(j);
                }
            }
        }
    }
    int min = Integer.MAX_VALUE;
    for (int i = 0; i < size; i++) {
        if (resultMap[size - 1][i] < min) {
            min = resultMap[size - 1][i];
        }
    }
    return min;
}

Version 2. Bottom-Up O(n^2) space

可以想成求从底部任一点出发到左上角的最小路径和 代码简洁 不会outOfBound

    public int minimumTotal(ArrayList < ArrayList < Integer >> triangle) {
    	if (triangle == null || triangle.size() == 0) {
    		return 0;
    	}
    	int size = triangle.size();
    	int[][] resultMap = new int[size][size];
    	//init the last row
    	ArrayList < Integer > lastRow = triangle.get(size - 1);
    	for (int i = 0; i < size; i++) {
    		resultMap[size - 1][i] = lastRow.get(i);
    	}
    	//from bottom to top
    	for (int i = size - 2; i >= 0; i--) {
    		ArrayList < Integer > curr = triangle.get(i);
    		for (int j = 0; j < curr.size(); j++) {
    			resultMap[i][j] = Math.min(resultMap[i + 1][j], resultMap[i + 1][j + 1]) + curr.get(j);
    		}
    	}
    	return resultMap[0][0];
    }

Version 3. Bottom-Up O(n) space

在Version 2的基础上 只用2*n的数组记录数据

代码不变 只需要行数mod 2 (modulus %) 就行了

    public int minimumTotal(ArrayList < ArrayList < Integer >> triangle) {
    	if (triangle == null || triangle.size() == 0) {
    		return 0;
    	}
    	int size = triangle.size();
    	int[][] resultMap = new int[2][size];
    	//init the last row
    	ArrayList < Integer > lastRow = triangle.get(size - 1);
    	for (int i = 0; i < size; i++) {
    		resultMap[(size - 1) % 2][i] = lastRow.get(i);
    	}
    	//from bottom to top
    	for (int i = size - 2; i >= 0; i--) {
    		ArrayList < Integer > curr = triangle.get(i);
    		for (int j = 0; j < curr.size(); j++) {
    			resultMap[i % 2][j] = Math.min(resultMap[(i + 1) % 2][j], resultMap[(i + 1) % 2][j + 1]) + curr.get(j);
    		}
    	}
    	return resultMap[0][0];
    }
FacebookTwitterGoogle+Share

Unique Path II

Follow up for “Unique Paths”:

Now consider if some obstacles are added to the grids. How many unique paths would there be?

An obstacle and empty space is marked as 1 and 0 respectively in the grid.

Example

For example,

There is one obstacle in the middle of a 3×3 grid as illustrated below.

[
  [0,0,0],
  [0,1,0],
  [0,0,0]
]

The total number of unique paths is 2.

Note

m and n will be at most 100.

    public int uniquePathsWithObstacles(int[][] obstacleGrid) {
    	// write your code here
    	if (obstacleGrid == null || obstacleGrid.length == 0 || obstacleGrid[0].length == 0 || obstacleGrid[0][0] == 1) {
    		return 0;
    	}
    	int row = obstacleGrid.length;
    	int col = obstacleGrid[0].length;
    	int[][] path = new int[row][col];
    	path[0][0] = 1;
    	//init first col
    	for (int i = 1; i < row; i++) {
    		path[i][0] = obstacleGrid[i][0] == 1 ? 0 : path[i - 1][0];
    	}
    	//init first row
    	for (int j = 1; j < col; j++) {
    		path[0][j] = obstacleGrid[0][j] == 1 ? 0 : path[0][j - 1];
    	}
    	for (int i = 1; i < row; i++) {
    		for (int j = 1; j < col; j++) {
    			path[i][j] = obstacleGrid[i][j] == 1 ? 0 : path[i - 1][j] + path[i][j - 1];
    		}
    	}
    	return path[row - 1][col - 1];
    }

Lowest Common Ancestor

Given the root and two nodes in a Binary Tree. Find the lowest common ancestor(LCA) of the two nodes.

The lowest common ancestor is the node with largest depth which is the ancestor of both nodes.

Example

        4

/     \

3         7

/     \

5         6

For 3 and 5, the LCA is 4.

For 5 and 6, the LCA is 7.

For 6 and 7, the LCA is 7.

public TreeNode lowestCommonAncestor(TreeNode root, TreeNode A, TreeNode B) {
    if (root == null || root == A || root == B) {
        return root;
    }
    TreeNode left = lowestCommonAncestor(root.left, A, B);
    TreeNode right = lowestCommonAncestor(root.right, A, B);

    //both left and right are not null,
    //means A and B have to be in each of the subtrees
    if (left != null && right != null) {
        return root;
    }
    //if only left or right is not null,
    //means both A and B are in same subtree
    if (left != null) {
        return left;
    }
    if (right != null) {
        return right;
    }
    return null;
}

Binary Search Tree Iterator

Design an iterator over a binary search tree with the following rules:

  • Elements are visited in ascending order (i.e. an in-order traversal)
  • next() and hasNext() queries run in O(1) time in average.

Example

For the following binary search tree, in-order traversal by using iterator is [1, 6, 10, 11, 12]

   10
 /    \
1      11
 \       \
  6       12

Challenge

Extra memory usage O(h), h is the height of the tree.

Super Star: Extra memory usage O(1)

1. Inorder Traverse the BST into an arrayList – O(n) space and O(n) time

public class Solution {
    //@param root: The root of binary tree.
    ArrayList<TreeNode> nodes;
    int index;
    public Solution(TreeNode root) {
        //flattern the tree using in-order traversal
        nodes = new ArrayList<>();
        inOrderTraversal(root, nodes);
        index = 0;
    }

    public void inOrderTraversal(TreeNode root, ArrayList<TreeNode> result) {
        if (root == null) {
            return;
        }
        inOrderTraversal(root.left, result);
        result.add(root);
        inOrderTraversal(root.right, result);
    }

    //@return: True if there has next node, or false
    public boolean hasNext() {
        return index < nodes.size();
    }

    //@return: return next node
    public TreeNode next() {
        if (index < nodes.size()) {
            return nodes.get(index++);
        }
        return null;
    }
}

2. O(h) space – h is the height of the tree
Have a stack which only contains the left-most nodes and its ancestors, so that it takes O(h) space. And for each node, the average time complexity for next() is O(1).(Since the total time complexity is O(n))

public class Solution {
    //@param root: The root of binary tree.
    Stack<TreeNode> nodes;
    public Solution(TreeNode root) {
        nodes = new Stack<>();
        TreeNode runner = root;
        while (runner != null) {
            nodes.push(runner);
            runner = runner.left;
        }
    }

    //@return: True if there has next node, or false
    public boolean hasNext() {
        return !nodes.empty();
    }

    //@return: return next node
    public TreeNode next() {
        if (!nodes.empty()) {
            TreeNode curr = nodes.pop();
            if (curr.right != null) {
                TreeNode runner = curr.right;
                while (runner != null) {
                    nodes.push(runner);
                    runner = runner.left;
                }
            }
            return curr;
        }
        return null;
    }
}

3. O(1) space

Search Range in Binary Search Tree

Search Range in Binary Search Tree

Given two values k1 and k2 (where k1 < k2) and a root pointer to a Binary Search Tree. Find all the keys of tree in range k1 to k2. i.e. print all x such that k1<=x<=k2 and x is a key of given BST. Return all the keys in ascending order.

Example
For example, if k1 = 10 and k2 = 22, then your function should print 12, 20 and 22.

20

/ \

8 22

/ \

4 12

public ArrayList<Integer> searchRange(TreeNode root, int k1, int k2) {
    ArrayList<Integer> result = new ArrayList<>();
    searchRangeHelper(root, k1, k2, result);
    return result;
}

public void searchRangeHelper(TreeNode root, int min, int max,
                              ArrayList<Integer> result) {
    if (root == null || min > max) {
        return;
    }
    if (root.val < min) {
        searchRangeHelper(root.right, min, max, result);
    } else if (root.val > max) {
        searchRangeHelper(root.left, min, max, result);
    } else {
        searchRangeHelper(root.left, min, root.val - 1, result);
        result.add(root.val);
        searchRangeHelper(root.right, root.val + 1, max, result);
    }
}

Binary Tree Maximum Path Sum

Given a binary tree, find the maximum path sum.

The path may start and end at any node in the tree.

Example

Given the below binary tree:

<code>  1
 / \
2   3
</code>

return 6.

private class maxPathResult {
    int maxSinglePath;
    int maxPath;
    public maxPathResult(int maxSinglePath, int maxPath) {
        this.maxSinglePath = maxSinglePath;//start from root to any nodes
        this.maxPath = maxPath;//max path in the tree
    }
}
public int maxPathSum(TreeNode root) {
    // write your code here
    return helper(root).maxPath;
}

public maxPathResult helper(TreeNode root) {
    if (root == null) {
        return new maxPathResult(Integer.MIN_VALUE, Integer.MIN_VALUE);
    }
    maxPathResult left = helper(root.left);
    maxPathResult right = helper(root.right);

    int maxSinglePath = Math.max(left.maxSinglePath, right.maxSinglePath);
    maxSinglePath = maxSinglePath < 0 ? root.val : root.val + maxSinglePath;

    int maxDoublePath = 0;
    if (left.maxSinglePath > 0) {
        maxDoublePath += left.maxSinglePath;
    }
    if (right.maxSinglePath > 0) {
        maxDoublePath += right.maxSinglePath;
    }
    maxDoublePath += root.val;

    int maxPath = Math.max(Math.max(left.maxPath, right.maxPath), maxDoublePath);
    return new maxPathResult(maxSinglePath, maxPath);
}

计算树的最长path有2种情况:

1. 通过根的path.

(1)如果左子树从左树根到任何一个Node的path大于零,可以链到root上

(2)如果右子树从右树根到任何一个Node的path大于零,可以链到root上

2. 不通过根的path. 这个可以取左子树及右子树的path的最大值。

所以创建一个inner class:

记录2个值:

1. 本树的最大path。

2. 本树从根节点出发到任何一个节点的最大path.

注意,当root == null,以上2个值都要置为Integer_MIN_VALUE; 因为没有节点可取的时候,是不存在solution的。以免干扰递归的计算

九章详解

Median of Two Sorted Arrays

There are two sorted arrays nums1 and nums2 of size m and n respectively. Find the median of the two sorted arrays. The overall run time complexity should be O(log (m+n)).

    public double findMedianSortedArrays(int[] A, int[] B) {
        if (A == null || B == null) {
            return -1; //or throw error
        }
        int size = A.length + B.length;
        if (size % 2 == 0) {
            return (findMedianHelper(A, 0, B, 0, size / 2) + findMedianHelper(A, 0, B, 0, size / 2 + 1)) / 2.0;
        } else {
            return findMedianHelper(A, 0, B, 0, size / 2 + 1);
        }
    }

    //find kth element from array A and B which starts from aStart and bStart
    public double findMedianHelper(int[] A, int aStart, int[] B, int bStart, int k) {
        if (aStart >= A.length) {
            return B[bStart + k - 1];
        }
        if (bStart >= B.length) {
            return A[aStart + k - 1];
        }
        if (k == 1) {
            return Math.min(A[aStart], B[bStart]);
        }

        int aPivot = aStart + k / 2 - 1 < A.length ? A[aStart + k / 2 - 1] : Integer.MAX_VALUE;
        int bPivot = bStart + k / 2 - 1 < B.length ? B[bStart + k / 2 - 1] : Integer.MAX_VALUE;

        if (aPivot < bPivot) {
            return findMedianHelper(A, aStart + k / 2, B, bStart, k - k / 2);
        } else {
            return findMedianHelper(A, aStart, B, bStart + k / 2, k - k / 2);
        }
    }

Follow Up Questions:

Now we have N machines, on each there is a sorted array, how to scale it to work together and efficiently find Kth element over all.

Solution 1:

N/2 group, each group has two machine. In each group, do only keep kth of two sorted array, then divide into n/4 groups, each group has 2 machine, keep kth of two sorted arrays again.

Time Complexity: O(K*lgN)

Solution 2:

二分答案S,将S广播给每台机器,每台机器用二分法求得有多少比该数小的数。汇总结果后可判断是该将S往上还是往下调整。总共最大的数是max, 最小的数是min,

s = (max+min)/2

然后你把s 拿到n台机器上去二分找有多少个数比他小, 如果有x个数比他小,

那么x< k 的话, min = s, x> k的话,max =s, 继续这个过程