Thursday, June 9, 2016

Leetcode: 327. Count of Range Sum

Given an integer array nums, return the number of range sums that lie in [lower, upper] inclusive.
Range sum S(i, j) is defined as the sum of the elements in nums between indices i and j (i ≤ j), inclusive.
Note:
A naive algorithm of O(n2) is trivial. You MUST do better than that.
Example:
Given nums = [-2, 5, -1]lower = -2upper = 2,
Return 3.
The three ranges are : [0, 0][2, 2][0, 2] and their respective sums are: -2, -1, 2.
Solution 1: Use Segment Tree

Solution 2: Use Binary Search Tree

Tuesday, December 22, 2015

Leetcode: Range Sum Query - Mutable

Given an integer array nums, find the sum of the elements between indices i and j (i ≤ j), inclusive.
The update(i, val) function modifies nums by updating the element at index i to val.
Example:
Given nums = [1, 3, 5]

sumRange(0, 2) -> 9
update(1, 2)
sumRange(0, 2) -> 8
Note:
  1. The array is only modifiable by the update function.
  2. You may assume the number of calls to update and sumRange function is distributed evenly.
Naive Solution 1: 
The first method is the most straight-forward. Use an array to store the numbers. So the update takes O(1) time. sumRange() takes O(n) time. 

Naive Solution 2:
Similar to the Range Sum Query - Immutable, we calculate the prefix of the elements in the array. Therefore, for the update(), it takes O(n) time to update the elements after the updated element. But the sumRange() take O(1) time. 

Better Solution:
Since the problem assumes that the two functions are called evenly, there exists a better method using Segment Tree in O(logn) time. 

Code (Java):
public class NumArray {
    class SegmentTreeNode {
        int start, end;
        int sum;
        SegmentTreeNode left, right;
        
        // Constructor
        public SegmentTreeNode(int start, int end) {
            this.start = start;
            this.end = end;
            sum = 0;
        }
        
        public SegmentTreeNode(int start, int end, int sum) {
            this.start = start;
            this.end = end;
            this.sum = sum;
        }
        
    }
    
    private SegmentTreeNode root;
    
    public NumArray(int[] nums) {
        if (nums == null || nums.length == 0) {
            return;
        }
        root = buildSegmentTree(nums, 0, nums.length - 1);
    }

    void update(int i, int val) {
        updateHelper(root, i, val);
    }
    
    private void updateHelper(SegmentTreeNode root, int i, int val) {
        if (root == null) {
            return;
        }
        
        int mid = root.start + (root.end - root.start) / 2;
        
        if (i <= mid) {
            updateHelper(root.left, i, val);
        } else {
            updateHelper(root.right, i, val);
        }
        
        if (root.start == root.end && root.start == i) {
            root.sum = val;
            return;
        }
        
        root.sum = root.left.sum + root.right.sum;

    }

    public int sumRange(int i, int j) {
        return sumRangeHelper(root, i, j);
    }
    
    private int sumRangeHelper(SegmentTreeNode root, int start, int end) {
        if (root == null || end < root.start || start > root.end || 
            start > end) {
            return 0;
        }
        
        if (start <= root.start && end >= root.end) {
            return root.sum;
        }
        
        int mid = root.start + (root.end - root.start) / 2;
        
        return sumRangeHelper(root.left, start, Math.min(end, mid)) + 
               sumRangeHelper(root.right, Math.max(mid + 1, start), end);
    }
    
    private SegmentTreeNode buildSegmentTree(int[] nums, int start, int end) {
        if (nums == null || nums.length == 0 || start > end) {
            return null;
        }
        
        // Start == end
        if (start == end) {
            return new SegmentTreeNode(start, end, nums[start]);
        }
        
        SegmentTreeNode root = new SegmentTreeNode(start, end);
        int mid = start + (end - start) / 2;
        root.left = buildSegmentTree(nums, start, mid);
        root.right = buildSegmentTree(nums, mid + 1, end);
        
        root.sum = root.left.sum + root.right.sum;
        
        return root;
    }
}


// Your NumArray object will be instantiated and called as such:
// NumArray numArray = new NumArray(nums);
// numArray.sumRange(0, 1);
// numArray.update(1, 10);
// numArray.sumRange(1, 2);

Summary:
The take-away message for this problem is there is no such a BEST solution ever. You need to communicate with the interviewer to ask the use cases and choose the best solution. 

Update on 5/16/19:
class NumArray {
    SegmentTree segmentTree;

    public NumArray(int[] nums) {
        segmentTree = new SegmentTree(nums);
    }
    
    public void update(int i, int val) {
        segmentTree.update(i, val);
    }
    
    public int sumRange(int i, int j) {
        return segmentTree.search(i, j);
    }
}

class SegmentTree {
    public SegmentTreeNode root;
    public SegmentTree(int[] nums) {
        root = build(nums);
    }
    
    public int search(int start, int end) {
        return searchHelper(root, start, end);
    }
    
    private int searchHelper(SegmentTreeNode root, int start, int end) {
        if (root == null || start > end) {
            return 0;
        }
        
        if (root.start == start && root.end == end) {
            return root.sum;
        }
        
        int mid = root.start + (root.end - root.start) / 2;
        int leftSum = searchHelper(root.left, Math.max(root.start, start), Math.min(mid, end));
        int rightSum = searchHelper(root.right, Math.max(start, mid + 1), Math.min(root.end, end));
        
        return leftSum + rightSum;
    }
    
    public void update(int index, int val) {
        updateHelper(root, index, val);
    }
    
    private void updateHelper(SegmentTreeNode root, int index, int val) {
        if (root == null) {
            return;
        }
        
        if (root.start == root.end && index == root.start) {
            root.sum = val;
            return;
        }
        
        int mid = root.start + (root.end - root.start) / 2;
        if (index <= mid) {
            updateHelper(root.left, index, val);
        } else {
            updateHelper(root.right, index, val);
        }
        
        root.sum = root.left.sum + root.right.sum;
    } 
    
    private SegmentTreeNode build(int[] nums) {
        return buildHelper(0, nums.length - 1, nums);
    }
    
    private SegmentTreeNode buildHelper(int start, int end, int[] nums) {
        if (start == end) {
            return new SegmentTreeNode(start, end, nums[start]);
        }
        
        int mid = start + (end - start) / 2;
        SegmentTreeNode leftChild = buildHelper(start, mid, nums);
        SegmentTreeNode rightChild = buildHelper(mid + 1, end, nums);
        
        SegmentTreeNode root = new SegmentTreeNode(start, end, leftChild.sum + rightChild.sum);
        root.left = leftChild;
        root.right = rightChild;
        
        return root;
    }
    
}

class SegmentTreeNode {
    int sum;
    int start, end;
    SegmentTreeNode left, right;
    
    public SegmentTreeNode(int start, int end, int sum) {
        this.sum = sum;
        this.start = start;
        this.end = end;
        left = right = null;
    }
}

/**
 * Your NumArray object will be instantiated and called as such:
 * NumArray obj = new NumArray(nums);
 * obj.update(i,val);
 * int param_2 = obj.sumRange(i,j);
 */

Monday, November 30, 2015

LintCode: Segment Tree Query II

For an array, we can build a SegmentTree for it, each node stores an extra attribute count to denote the number of elements in the the array which value is between interval start and end. (The array may not fully filled by elements)
Design a query method with three parameters rootstart and end, find the number of elements in the in array's interval [startend] by the given root of value SegmentTree.
Example
For array [0, 2, 3], the corresponding value Segment Tree is:
                     [0, 3, count=3]
                     /             \
          [0,1,count=1]             [2,3,count=2]
          /         \               /            \
   [0,0,count=1] [1,1,count=0] [2,2,count=1], [3,3,count=1]
query(1, 1), return 0
query(1, 2), return 1
query(2, 3), return 2
query(0, 2), return 2

Code(Java):
/**
 * Definition of SegmentTreeNode:
 * public class SegmentTreeNode {
 *     public int start, end, count;
 *     public SegmentTreeNode left, right;
 *     public SegmentTreeNode(int start, int end, int count) {
 *         this.start = start;
 *         this.end = end;
 *         this.count = count;
 *         this.left = this.right = null;
 *     }
 * }
 */
public class Solution {
    /**
     *@param root, start, end: The root of segment tree and 
     *                         an segment / interval
     *@return: The count number in the interval [start, end]
     */
    public int query(SegmentTreeNode root, int start, int end) {
        // write your code here
        if (root == null || start > end) {
            return 0;
        }
        
        if (end < root.start || start > root.end) {
            return 0;
        }
        
        if (start <= root.start && end >= root.end) {
            return root.count;
        }
        
        int mid = root.start + (root.end - root.start) / 2;
        return query(root.left, start, Math.min(mid, end)) + 
               query(root.right, Math.max(mid + 1, start), end);
    }
}

Update on 5/6/19:
/**
 * Definition of SegmentTreeNode:
 * public class SegmentTreeNode {
 *     public int start, end, count;
 *     public SegmentTreeNode left, right;
 *     public SegmentTreeNode(int start, int end, int count) {
 *         this.start = start;
 *         this.end = end;
 *         this.count = count;
 *         this.left = this.right = null;
 *     }
 * }
 */



public class Solution {
    /*
     * @param root: The root of segment tree.
     * @param start: start value.
     * @param end: end value.
     * @return: The count number in the interval [start, end]
     */
    public int query(SegmentTreeNode root, int start, int end) {
        // write your code here
        if (root == null || start > end) {
            return 0;
        }

        if (end < root.start || start > root.end) {
            return 0;
        }

        if (start == root.start && end == root.end) {
            return root.count;
        }

        int mid = root.start + (root.end - root.start) / 2;

        int leftCount = query(root.left, Math.max(start, root.start), Math.min(mid, end));
        int rightCount = query(root.right, Math.max(mid + 1, start), Math.min(end, root.end));

        return leftCount + rightCount;
    }
}

LintCode: Segment Tree Query

For an integer array (index from 0 to n-1, where n is the size of this array), in the corresponding SegmentTree, each node stores an extra attribute max to denote the maximum number in the interval of the array (index from start to end).
Design a query method with three parameters rootstart and end, find the maximum number in the interval [start, end] by the given root of segment tree.
Example
For array [1, 4, 2, 3], the corresponding Segment Tree is:
                  [0, 3, max=4]
                 /             \
          [0,1,max=4]        [2,3,max=3]
          /         \        /         \
   [0,0,max=1] [1,1,max=4] [2,2,max=2], [3,3,max=3]
query(root, 1, 1), return 4
query(root, 1, 2), return 4
query(root, 2, 3), return 3
query(root, 0, 2), return 4
Note
It is much easier to understand this problem if you finished Segment Tree Build first.

Code (Java):
/**
 * Definition of SegmentTreeNode:
 * public class SegmentTreeNode {
 *     public int start, end, max;
 *     public SegmentTreeNode left, right;
 *     public SegmentTreeNode(int start, int end, int max) {
 *         this.start = start;
 *         this.end = end;
 *         this.max = max
 *         this.left = this.right = null;
 *     }
 * }
 */
public class Solution {
    /**
     *@param root, start, end: The root of segment tree and 
     *                         an segment / interval
     *@return: The maximum number in the interval [start, end]
     */
    public int query(SegmentTreeNode root, int start, int end) {
        // write your code here
        if (root == null || start > end) {
            return Integer.MIN_VALUE;
        }
        
        if (end < root.start || start > root.end) {
            return Integer.MIN_VALUE;
        }
        
        if (start == root.start && end == root.end) {
            return root.max;
        }
        
        int mid = root.start + (root.end - root.start) / 2;
        return Math.max(query(root.left, start, Math.min(mid, end)), 
                        query(root.right, Math.max(mid + 1, start), end));
    }
}

Update on 5/6/19:
/**
 * Definition of SegmentTreeNode:
 * public class SegmentTreeNode {
 *     public int start, end, max;
 *     public SegmentTreeNode left, right;
 *     public SegmentTreeNode(int start, int end, int max) {
 *         this.start = start;
 *         this.end = end;
 *         this.max = max
 *         this.left = this.right = null;
 *     }
 * }
 */

public class Solution {
    /**
     * @param root: The root of segment tree.
     * @param start: start value.
     * @param end: end value.
     * @return: The maximum number in the interval [start, end]
     */
    public int query(SegmentTreeNode root, int start, int end) {
        // write your code here
        if (root == null || start > end) {
            return Integer.MIN_VALUE;
        }

        if (end < root.start || start > root.end) {
            return Integer.MIN_VALUE;
        }

        if (start == root.start && end == root.end) {
            return root.max;
        }

        int mid = root.start + (root.end - root.start) / 2;
        if (end <= mid) {
            return query(root.left, start, end);
        } else if (start >= mid + 1) {
            return query(root.right, start, end);
        } else {
            int leftMax = query(root.left, start, mid);
            int rightMax = query(root.right, mid + 1, end);
            return Math.max(leftMax, rightMax);
        }
    }
}

LintCode: Segment Tree Build II

The structure of Segment Tree is a binary tree which each node has two attributes start and end denote an segment / interval.
start and end are both integers, they should be assigned in following rules:
  • The root's start and end is given by build method.
  • The left child of node A has start=A.left, end=(A.left + A.right) / 2.
  • The right child of node A has start=(A.left + A.right) / 2 + 1, end=A.right.
  • if start equals to end, there will be no children for this node.
Implement a build method with a given array, so that we can create a corresponding segment tree with every node value represent the corresponding interval max value in the array, return the root of this segment tree.
Example
Given [3,2,1,4]. The segment tree will be:
                 [0,  3] (max = 4)
                  /            \
        [0,  1] (max = 3)     [2, 3]  (max = 4)
        /        \               /             \
[0, 0](max = 3)  [1, 1](max = 2)[2, 2](max = 1) [3, 3] (max = 4)
Clarification
Segment Tree (a.k.a Interval Tree) is an advanced data structure which can support queries like:
  • which of these intervals contain a given point
  • which of these points are in a given interval

Code (Java):
/**
 * Definition of SegmentTreeNode:
 * public class SegmentTreeNode {
 *     public int start, end, max;
 *     public SegmentTreeNode left, right;
 *     public SegmentTreeNode(int start, int end, int max) {
 *         this.start = start;
 *         this.end = end;
 *         this.max = max
 *         this.left = this.right = null;
 *     }
 * }
 */
public class Solution {
    /**
     *@param A: a list of integer
     *@return: The root of Segment Tree
     */
    public SegmentTreeNode build(int[] A) {
        // write your code here
        if (A == null || A.length == 0) {
            return null;
        }
        
        return buildHelper(A, 0, A.length - 1);
    }
    
    private SegmentTreeNode buildHelper(int[] A, int lo, int hi) {
        if (lo > hi) {
            return null;
        }
        
        if (lo == hi) {
            SegmentTreeNode node = new SegmentTreeNode(lo, hi, A[lo]);
            return node;
        }
        
        int mid = lo + (hi - lo) / 2;
        SegmentTreeNode root = new SegmentTreeNode(lo, hi);
        
        root.left = buildHelper(A, lo, mid);
        root.right = buildHelper(A, mid + 1, hi);
        
        root.max = Math.max(root.left.max, root.right.max);
        
        return root;
    }
}

LintCode: Segment Tree Build

The structure of Segment Tree is a binary tree which each node has two attributes start and end denote an segment / interval.
start and end are both integers, they should be assigned in following rules:
  • The root's start and end is given by build method.
  • The left child of node A has start=A.left, end=(A.left + A.right) / 2.
  • The right child of node A has start=(A.left + A.right) / 2 + 1, end=A.right.
  • if start equals to end, there will be no children for this node.
Implement a build method with two parameters start and end, so that we can create a corresponding segment tree with every node has the correct start and end value, return the root of this segment tree.
Example
Given start=0, end=3. The segment tree will be:
               [0,  3]
             /        \
      [0,  1]           [2, 3]
      /     \           /     \
   [0, 0]  [1, 1]     [2, 2]  [3, 3]
Given start=1, end=6. The segment tree will be:
               [1,  6]
             /        \
      [1,  3]           [4,  6]
      /     \           /     \
   [1, 2]  [3,3]     [4, 5]   [6,6]
   /    \           /     \
[1,1]   [2,2]     [4,4]   [5,5]
Clarification
Segment Tree (a.k.a Interval Tree) is an advanced data structure which can support queries like:
  • which of these intervals contain a given point
  • which of these points are in a given interval

Code (Java):
/**
 * Definition of SegmentTreeNode:
 * public class SegmentTreeNode {
 *     public int start, end;
 *     public SegmentTreeNode left, right;
 *     public SegmentTreeNode(int start, int end) {
 *         this.start = start, this.end = end;
 *         this.left = this.right = null;
 *     }
 * }
 */
public class Solution {
    /**
     *@param start, end: Denote an segment / interval
     *@return: The root of Segment Tree
     */
    public SegmentTreeNode build(int start, int end) {
        // write your code here
        if (start > end) {
            return null;
        }
        
        if (start == end) {
            SegmentTreeNode node = new SegmentTreeNode(start, end);
            return node;
        }
        
        int mid = start + (end - start) / 2;
        SegmentTreeNode root = new SegmentTreeNode(start, end);
        root.left = build(start, mid);
        root.right = build(mid + 1, end);
        
        return root;
    }
}



Wednesday, September 2, 2015

Leetcode: Implement Queue using Stacks

Implement the following operations of a queue using stacks.
  • push(x) -- Push element x to the back of queue.
  • pop() -- Removes the element from in front of queue.
  • peek() -- Get the front element.
  • empty() -- Return whether the queue is empty.
Notes:
  • You must use only standard operations of a stack -- which means only push to toppeek/pop from topsize, and is empty operations are valid.
  • Depending on your language, stack may not be supported natively. You may simulate a stack by using a list or deque (double-ended queue), as long as you use only standard operations of a stack.
  • You may assume that all operations are valid (for example, no pop or peek operations will be called on an empty queue).
Understand the problem:
The problem can be solved by using two stacks, stack1 and stack2.
  -- push(x), push an element into stack1. O(1) time complexity.
  -- pop(), check if the stack 2 is empty. If not, pop from stack2. If yes, pop all elements from stack1 and push into stack2. Then pop from stack2. Amortized time complexity is O(1).
  -- peek(). The same as pop().
  -- isEmpty(). Check if both stack1 and stack2 are empty.

Code (Java):
class MyQueue {
    private Stack<Integer> stack1;
    private Stack<Integer> stack2;
    
    public MyQueue() {
        this.stack1 = new Stack<Integer>();
        this.stack2 = new Stack<Integer>();
    }
    // Push element x to the back of queue.
    public void push(int x) {
        stack1.push(x);
    }

    // Removes the element from in front of queue.
    public void pop() {
        if (!stack2.isEmpty()) {
            stack2.pop();
        } else {
            while (!stack1.isEmpty()) {
                stack2.push(stack1.pop());
            }
            stack2.pop();
        }
    }

    // Get the front element.
    public int peek() {
        int ret = 0;
        if (!stack2.isEmpty()) {
            ret = stack2.peek();
        } else {
            while (!stack1.isEmpty()) {
                stack2.push(stack1.pop());
            }
            ret = stack2.peek();
        }
        
        return ret;
    }

    // Return whether the queue is empty.
    public boolean empty() {
        return stack1.isEmpty() && stack2.isEmpty();
    }
}

Leetcode: Implement Stack using Queues

mplement the following operations of a stack using queues.
  • push(x) -- Push element x onto stack.
  • pop() -- Removes the element on top of the stack.
  • top() -- Get the top element.
  • empty() -- Return whether the stack is empty.
Notes:
  • You must use only standard operations of a queue -- which means only push to backpeek/pop from frontsize, and is empty operations are valid.
  • Depending on your language, queue may not be supported natively. You may simulate a queue by using a list or deque (double-ended queue), as long as you use only standard operations of a queue.
  • You may assume that all operations are valid (for example, no pop or top operations will be called on an empty stack).
Update (2015-06-11):
The class name of the Java function had been updated to MyStack instead of Stack.
Credits:
Special thanks to @jianchao.li.fighter for adding this problem and all test cases.
Understand the problem:
We can use two queues, queue1 and queue2.
 -- push(x), push x into queue1. Time complexity O(1)
 -- pop(), dequeue all n - 1 elements and enqueue into queue2. dequeue the last element. 
Swap queue1 and queue2. Time complexity O(n).
 -- top() dequeue all n - 1 elements and enqueue into queue2, dequeue the last element and save the as return, then enqueue it into queue2. Swap queue1 and queue2. Time complexity is O(n).
 -- empty(), check if queue1 is empty. 

Code (Java):
class MyStack {
    private Queue<Integer> queue1;
    private Queue<Integer> queue2;
    
    public MyStack() {
        this.queue1 = new LinkedList<Integer>();
        this.queue2 = new LinkedList<Integer>();
    }
    
    // Push element x onto stack.
    public void push(int x) {
        queue1.offer(x);
    }

    // Removes the element on top of the stack.
    public void pop() {
        while (queue1.size() > 1) {
            queue2.offer(queue1.poll());
        }
        
        queue1.poll();
        
        // Swap queue1 and queue2
        Queue<Integer> temp = queue1;
        queue1 = queue2;
        queue2 = temp;
    }

    // Get the top element.
    public int top() {
        while (queue1.size() > 1) {
            queue2.offer(queue1.poll());
        }
        
        int ret = queue1.poll();
        queue2.offer(ret);
        
        // Swap queue 1 and queue2
        Queue<Integer> temp = queue1;
        queue1 = queue2;
        queue2 = temp;
        
        return ret;
    }

    // Return whether the stack is empty.
    public boolean empty() {
        return queue1.isEmpty();
    }
}

Monday, August 31, 2015

Leetcode: Kth Largest Element in an Array

Find the kth largest element in an unsorted array. Note that it is the kth largest element in the sorted order, not the kth distinct element.
For example,
Given [3,2,1,5,6,4] and k = 2, return 5.
Note: 
You may assume k is always valid, 1 ≤ k ≤ array's length.
Credits:
Special thanks to @mithmatt for adding this problem and creating all test cases.
A max-heap solution:
First of all, put all elements into the heap. Then poll the top k elements from the max heap then we get the result. The time complexity for max heap is  O(n) + O(k * logn). The space complexity is O(n).

Code (Java):
public class Solution {
    public int findKthLargest(int[] nums, int k) {
        if (nums == null || nums.length == 0) {
            return 0;
        }
        
        PriorityQueue<Integer> maxHeap = new PriorityQueue<>(nums.length, Collections.reverseOrder());
        
        for (int num : nums) {
            maxHeap.offer(num);
        }
        
        int result = 0;
        for (int i = 0; i < k; i++) {
            result = maxHeap.poll();
        }
        
        return result;
    }
}

A min-heap solution:
 -- Step 1: put the first k elements into the heap. Time complexity is O(k). 
 -- Step 2: Start from elements k + 1 to n, compare each one with heap.peek(). If greater than the peek, replace with the element. The time complexity is O((n - k) logk).
  -- Step 3: After we iterate the array, the heap stores the top k elements, and the kth largest element is the minimum element of the heap, which is peek.

The space complexity is O(k). 

Code (Java):
public class Solution {
    public int findKthLargest(int[] nums, int k) {
        if (nums == null || nums.length == 0) {
            return 0;
        }
        
        PriorityQueue<Integer> maxHeap = new PriorityQueue<>(k);
        
        for (int num : nums) {
            if (maxHeap.size() < k) {
                maxHeap.offer(num);
            } else {
                if (num > maxHeap.peek()) {
                    maxHeap.poll();
                    maxHeap.offer(num);
                }
            }
        }
        
        return maxHeap.peek();
    }
}


A quick-selection algorithm:
The quick selection algorithm is very similar to quick sort. Instead of sorting, it only needs the partition step, where it finds the pivot and compare the pivot with k. 

There is post for the quick sort. 
http://buttercola.blogspot.com/2014/12/data-structure-algorithms-sorting.html

Code (Java):
public class Solution {
    public int findKthLargest(int[] nums, int k) {
        if (nums == null || nums.length == 0) {
            return 0;
        }
        
        return findKthLargestHelper(nums, 0, nums.length - 1, nums.length - k);
    }
    
    private int findKthLargestHelper(int[] nums, int lo, int hi, int k) {
        if (lo >= hi) {
            return nums[lo];
        }
        
        int pivot = partition(nums, lo, hi);
        if (pivot == k) {
            return nums[k];
        }
        
        if (pivot > k) {
            return findKthLargestHelper(nums, lo, pivot - 1, k);
        } else {
            return findKthLargestHelper(nums, pivot + 1, hi, k);
        }
    }
    
    private int partition(int[] nums, int lo, int hi) {
        int pivot = nums[lo];
        int i = lo + 1;
        int j = hi;
        
        while (i <= j) {
            while (i <= j && nums[i] < pivot) {
                i++;
            }
            
            while (i <= j && nums[j] >= pivot) {
                j--;
            }
            
            if (i <= j) {
                swap(nums, i, j);
            }
        }
        
        swap(nums, lo, j);
        
        return j;
    }
    
    private void swap(int[] nums, int i, int j) {
        int temp = nums[i];
        nums[i] = nums[j];
        nums[j] = temp;
    }
}


Since it only uses the partition algorithm, the average time complexity is O(n). However, the worst case complexity is O(n^2). 

In which case the quick selection has time complexity of O(n^2)?
Let's say you have a sorted array, 1 2 3 4 5, and k = 1, means we select the largest element which is 5. For each element in the array, we need to run the partition algorithm and discard the pivot only, which has the time complexity of O(n). For the n elements in the array, the overall time complexity is O(n^2). Therefore, for either quick sort and quick select algorithm, we usually need to well suffle the array for the reason each time the pivot is chosen in the half.

Leetcode: Add and Search Word - Data structure design

Design a data structure that supports the following two operations:
void addWord(word)
bool search(word)
search(word) can search a literal word or a regular expression string containing only letters a-z or .. A . means it can represent any one letter.
For example:
addWord("bad")
addWord("dad")
addWord("mad")
search("pad") -> false
search("bad") -> true
search(".ad") -> true
search("b..") -> true
Note:
You may assume that all words are consist of lowercase letters a-z.
You should be familiar with how a Trie works. If not, please work on this problem: Implement Trie (Prefix Tree) first.

Understand the problem:
Use Trie + DFS

Code (Java):
public class WordDictionary {
    class TrieNode {
        char val;
        boolean leaf;
        TrieNode[] children;
        
        public TrieNode() {
            this.val = '\0';
            this.leaf = false;
            this.children = new TrieNode[26];
        }
        
        public TrieNode(char val, boolean leaf) {
            this.val = val;
            this.leaf = leaf;
            this.children = new TrieNode[26];
        }
    }
    
    private TrieNode root = new TrieNode();
    private TrieNode dummyRoot = root;
    
    // Adds a word into the data structure.
    public void addWord(String word) {
        TrieNode curr = root;
        int offset = 'a';
        int i = 0;
        for (i = 0; i < word.length(); i++) {
            char character = word.charAt(i);
            if (curr.children[character - offset] == null) {
                curr.children[character - offset] = 
                    new TrieNode(character, i == word.length() - 1 ? true : false);
            } else {
                if (i == word.length() - 1) {
                    curr.children[character - offset].leaf = true;
                }
            }
            
            curr = curr.children[character - offset];
        }
    }

    // Returns if the word is in the data structure. A word could
    // contain the dot character '.' to represent any one letter.
    public boolean search(String word) {
        if (word == null || word.length() == 0) {
            return false;
        }
        
        TrieNode curr = root;
        int offset = 'a';
        for (int i = 0; i < word.length(); i++) {
            char character = word.charAt(i);
            if (character != '.') {
                if (curr.children[character - offset] == null) {
                    return false;
                }
                curr = curr.children[character - offset];
            } else {
                // DFS
                for (int j = 0; j < 26; j++) {
                    if (curr.children[j] != null) {
                        if (i == word.length() - 1 && curr.children[j].leaf) {
                            root = dummyRoot;
                            return true;
                        }
                        
                        root = curr.children[j];
                        if (search(word.substring(i + 1))) {
                            root = dummyRoot;
                            return true;
                        }
                    }
                }
                root = dummyRoot;
                return false;
            }
        }
        
        if (curr != null && curr.leaf == false) {
            return false;
        }
        
        return true;
    }
}

// Your WordDictionary object will be instantiated and called as such:
// WordDictionary wordDictionary = new WordDictionary();
// wordDictionary.addWord("word");
// wordDictionary.search("pattern");


Update on 10/19/15:
Updated neat version without saving the value for a TrieNode. 
There are mainly two tricks in the problem:
  -- The first trick is, in the DFS, we need to change the root of the Trie, and don't forget to change it back. 
  -- The second trick is, when we tried all 26 possibilities without getting an answer, we must return false instead. 

public class WordDictionary {
    private Trie trie = new Trie();
    
    // Adds a word into the data structure.
    public void addWord(String word) {
        trie.add(word);
    }

    // Returns if the word is in the data structure. A word could
    // contain the dot character '.' to represent any one letter.
    public boolean search(String word) {
        return trie.search(word);
    }
    
    class Trie {
        private TrieNode root = new TrieNode();
        private TrieNode rootCopy = root;
        
        // Add a word
        void add(String word) {
            TrieNode p = root;
            
            for (int i = 0; i < word.length(); i++) {
                char c = word.charAt(i);
                if (p.children[c- 'a'] != null) {
                    p = p.children[c - 'a'];
                } else {
                    p.children[c - 'a'] = new TrieNode();
                    p = p.children[c - 'a'];
                }
                
                if (i == word.length() - 1) {
                    p.leaf = true;
                }
            }
        }
        
        boolean search(String word) {
            TrieNode p = root;
            
            for (int i = 0; i < word.length(); i++) {
                char c = word.charAt(i);
                
                if (c == '.') {
                    for (int j = 0; j < 26; j++) {
                        if (p.children[j] != null) {
                            // Change the root pointer
                            root = p.children[j];
                            
                            if (search(word.substring(i + 1))) {
                                root = rootCopy;
                                return true;
                            }
                            
                            // Change back the root pointer
                            root = rootCopy;
                        }
                    }
                    // If none of them get true, return false;                   
                    return false;
                } else {
                    if (p.children[c - 'a'] == null) {
                        return false;
                    }
                    p = p.children[c - 'a'];
                }
            }
            
            if (!p.leaf) {
                return false;
            }
            
            return true;
        }
    }
    
    class TrieNode {
        TrieNode[] children;
        boolean leaf;
        
        public TrieNode() {
            children = new TrieNode[26];
        }
    }
}

// Your WordDictionary object will be instantiated and called as such:
// WordDictionary wordDictionary = new WordDictionary();
// wordDictionary.addWord("word");
// wordDictionary.search("pattern");

Friday, December 12, 2014

Data Structure & Algorithms : Hash Tables

Hash Function:  the hash function that we use uniformly distributes keys among the integer values between 0 and M-1.

How to resolve Hash Collision?

Hashing with separate chaining.
A hash function converts keys into array indices. The second component of a hashing algorithm is collision resolution: a strategy for handling the case when two or more keys to be inserted hash to the same index. A straightforward approach to collision resolution is to build, for each of the M array indices, a linked list of the key-value pairs whose keys hash to that index. The basic idea is to choose M to be sufficiently large that the lists are sufficiently short to enable efficient search through a two-step process: hash to find the list that could contain the key, then sequentially search through that list for the key.

hashing with separate chaining

Code (Java):
/*************************************************************************
 *  Compilation:  javac SeparateChainingHashST.java
 *  Execution:    java SeparateChainingHashST
 *
 *  A symbol table implemented with a separate-chaining hash table.
 * 
 *  % java SeparateChainingHashST
 *
 *************************************************************************/

public class SeparateChainingHashST&lt;Key, Value> {
    private static final int INIT_CAPACITY = 4;

    // largest prime <= 2^i for i = 3 to 31
    // not currently used for doubling and shrinking
    // private static final int[] PRIMES = {
    //    7, 13, 31, 61, 127, 251, 509, 1021, 2039, 4093, 8191, 16381,
    //    32749, 65521, 131071, 262139, 524287, 1048573, 2097143, 4194301,
    //    8388593, 16777213, 33554393, 67108859, 134217689, 268435399,
    //    536870909, 1073741789, 2147483647
    // };

    private int N;                                // number of key-value pairs
    private int M;                                // hash table size
    private SequentialSearchST<Key, Value>[] st;  // array of linked-list symbol tables


    // create separate chaining hash table
    public SeparateChainingHashST() {
        this(INIT_CAPACITY);
    } 

    // create separate chaining hash table with M lists
    public SeparateChainingHashST(int M) {
        this.M = M;
        st = (SequentialSearchST<Key, Value>[]) new SequentialSearchST[M];
        for (int i = 0; i < M; i++)
            st[i] = new SequentialSearchST<Key, Value>();
    } 

    // resize the hash table to have the given number of chains b rehashing all of the keys
    private void resize(int chains) {
        SeparateChainingHashST<Key, Value> temp = new SeparateChainingHashST<Key, Value>(chains);
        for (int i = 0; i < M; i++) {
            for (Key key : st[i].keys()) {
                temp.put(key, st[i].get(key));
            }
        }
        this.M  = temp.M;
        this.N  = temp.N;
        this.st = temp.st;
    }

    // hash value between 0 and M-1
    private int hash(Key key) {
        return (key.hashCode() & 0x7fffffff) % M;
    } 

    // return number of key-value pairs in symbol table
    public int size() {
        return N;
    } 

    // is the symbol table empty?
    public boolean isEmpty() {
        return size() == 0;
    }

    // is the key in the symbol table?
    public boolean contains(Key key) {
        return get(key) != null;
    } 

    // return value associated with key, null if no such key
    public Value get(Key key) {
        int i = hash(key);
        return st[i].get(key);
    } 

    // insert key-value pair into the table
    public void put(Key key, Value val) {
        if (val == null) {
            delete(key);
            return;
        }

        // double table size if average length of list >= 10
        if (N >= 10*M) resize(2*M);

        int i = hash(key);
        if (!st[i].contains(key)) N++;
        st[i].put(key, val);
    } 

    // delete key (and associated value) if key is in the table
    public void delete(Key key) {
        int i = hash(key);
        if (st[i].contains(key)) N--;
        st[i].delete(key);

        // halve table size if average length of list <= 2
        if (M > INIT_CAPACITY && N <= 2*M) resize(M/2);
    } 

    // return keys in symbol table as an Iterable
    public Iterable<Key> keys() {
        Queue<Key> queue = new Queue<Key>();
        for (int i = 0; i < M; i++) {
            for (Key key : st[i].keys())
                queue.enqueue(key);
        }
        return queue;
    } 


   /***********************************************************************
    *  Unit test client.
    ***********************************************************************/
    public static void main(String[] args) { 
        SeparateChainingHashST<String, Integer> st = new SeparateChainingHashST<String, Integer>();
        for (int i = 0; !StdIn.isEmpty(); i++) {
            String key = StdIn.readString();
            st.put(key, i);
        }

        // print keys
        for (String s : st.keys()) 
            StdOut.println(s + " " + st.get(s)); 

    }

}

Hashing with linear probing.

 Another approach to implementing hashing is to store N key-value pairs in a hash table of size M > N, relying on empty entries in the table to help with with collision resolution. Such methods are called open-addressing hashing methods. The simplest open-addressing method is called linear probing: when there is a collision (when we hash to a table index that is already occupied with a key different from the search key), then we just check the next entry in the table (by incrementing the index). There are three possible outcomes:
  • key equal to search key: search hit
  • empty position (null key at indexed position): search miss
  • key not equal to search key: try next entry
hashing with linear probing

Code (Java):
/*************************************************************************
 *  Compilation:  javac LinearProbingHashST.java
 *  Execution:    java LinearProbingHashST
 *  
 *  Symbol table implementation with linear probing hash table.
 *
 *  % java LinearProbingHashST
 *  128.112.136.11
 *  208.216.181.15
 *  null
 *
 *
 *************************************************************************/


public class LinearProbingHashST<Key, Value> {
    private static final int INIT_CAPACITY = 4;

    private int N;           // number of key-value pairs in the symbol table
    private int M;           // size of linear probing table
    private Key[] keys;      // the keys
    private Value[] vals;    // the values


    // create an empty hash table - use 16 as default size
    public LinearProbingHashST() {
        this(INIT_CAPACITY);
    }

    // create linear proving hash table of given capacity
    public LinearProbingHashST(int capacity) {
        M = capacity;
        keys = (Key[])   new Object[M];
        vals = (Value[]) new Object[M];
    }

    // return the number of key-value pairs in the symbol table
    public int size() {
        return N;
    }

    // is the symbol table empty?
    public boolean isEmpty() {
        return size() == 0;
    }

    // does a key-value pair with the given key exist in the symbol table?
    public boolean contains(Key key) {
        return get(key) != null;
    }

    // hash function for keys - returns value between 0 and M-1
    private int hash(Key key) {
        return (key.hashCode() & 0x7fffffff) % M;
    }

    // resize the hash table to the given capacity by re-hashing all of the keys
    private void resize(int capacity) {
        LinearProbingHashST<Key, Value> temp = 
            new LinearProbingHashST<Key, Value>(capacity);
        for (int i = 0; i < M; i++) {
            if (keys[i] != null) {
                temp.put(keys[i], vals[i]);
            }
        }
        keys = temp.keys;
        vals = temp.vals;
        M    = temp.M;
    }

    // insert the key-value pair into the symbol table
    public void put(Key key, Value val) {
        if (val == null) {
            delete(key);
            return;
        }

        // double table size if 50% full
        if (N >= M/2) resize(2*M);

        int i;
        for (i = hash(key); keys[i] != null; i = (i + 1) % M) {
            if (keys[i].equals(key)) { vals[i] = val; return; }
        }
        keys[i] = key;
        vals[i] = val;
        N++;
    }

    // return the value associated with the given key, null if no such value
    public Value get(Key key) {
        for (int i = hash(key); keys[i] != null; i = (i + 1) % M) 
            if (keys[i].equals(key))
                return vals[i];
        return null;
    }

    // delete the key (and associated value) from the symbol table
    public void delete(Key key) {
        if (!contains(key)) return;

        // find position i of key
        int i = hash(key);
        while (!key.equals(keys[i])) {
            i = (i + 1) % M;
        }

        // delete key and associated value
        keys[i] = null;
        vals[i] = null;

        // rehash all keys in same cluster
        i = (i + 1) % M;
        while (keys[i] != null) {
            // delete keys[i] an vals[i] and reinsert
            Key   keyToRehash = keys[i];
            Value valToRehash = vals[i];
            keys[i] = null;
            vals[i] = null;
            N--;  
            put(keyToRehash, valToRehash);
            i = (i + 1) % M;
        }

        N--;        

        // halves size of array if it's 12.5% full or less
        if (N > 0 && N <= M/8) resize(M/2);

        assert check();
    }

    // return all of the keys as in Iterable
    public Iterable<Key> keys() {
        Queue<Key> queue = new Queue<Key>();
        for (int i = 0; i < M; i++)
            if (keys[i] != null) queue.enqueue(keys[i]);
        return queue;
    }

    // integrity check - don't check after each put() because
    // integrity not maintained during a delete()
    private boolean check() {

        // check that hash table is at most 50% full
        if (M < 2*N) {
            System.err.println("Hash table size M = " + M + "; array size N = " + N);
            return false;
        }

        // check that each key in table can be found by get()
        for (int i = 0; i < M; i++) {
            if (keys[i] == null) continue;
            else if (get(keys[i]) != vals[i]) {
                System.err.println("get[" + keys[i] + "] = " 
                  + get(keys[i]) + "; vals[i] = " + vals[i]);
                return false;
            }
        }
        return true;
    }


/***********************************************************************
    *  Unit test client.
    ***********************************************************************/
    public static void main(String[] args) { 
        LinearProbingHashST<String, Integer> st = new LinearProbingHashST<String, Integer>();
        for (int i = 0; !StdIn.isEmpty(); i++) {
            String key = StdIn.readString();
            st.put(key, i);
        }

        // print keys
        for (String s : st.keys()) 
            StdOut.println(s + " " + st.get(s)); 
    }
}