2014年11月30日星期日

[Leetcode] Count and Say

The count-and-say sequence is the sequence of integers beginning as follows:
1, 11, 21, 1211, 111221, ...
1 is read off as "one 1" or 11.
11 is read off as "two 1s" or 21.
21 is read off as "one 2, then one 1" or 1211.

Given an integer n, generate the nth sequence.
Note: The sequence of integers will be represented as a string.

Simple string manipulation problem, mainly about finding repeating characters sequences. I used two pointers to find the continuous characters.

    public String countAndSay(int n) {
        String str = "1";
        while(n > 1) {
            int p1 = 0, p2 = 0;
            StringBuffer sb = new StringBuffer();
            while(p1 < str.length()) {
                while(p2 < str.length() && str.charAt(p1) == str.charAt(p2))
                    p2++;
                sb.append(String.valueOf(p2 - p1));
                sb.append(str.charAt(p1));
                p1 = p2;
            }
            str = sb.toString();
            n--;
        }
        return str;
    }

[Leetcode] Reverse Integer

Reverse digits of an integer.
Example1: x = 123, return 321
Example2: x = -123, return -321

Have you thought about this? Here are some good questions to ask before coding. Bonus points for you if you have already thought through this!
If the integer's last digit is 0, what should the output be? ie, cases such as 10, 100.
Did you notice that the reversed integer might overflow? Assume the input is a 32-bit integer, then the reverse of 1000000003 overflows. How should you handle such cases?
For the purpose of this problem, assume that your function returns 0 when the reversed integer overflows.
Update (2014-11-10):
Test cases had been added to test the overflow behavior.

Pay attention to the case of overflow and the case when x = Integer.MIN_VALUE. In this case, you could not directly let x = -x, since it would overflow again, but we know for sure that the reverse of it would overflow so we could directly return 0.

    public int reverse(int x) {
        boolean sign = true;
        if(x < 0) {
            sign = false;
            if(x == Integer.MIN_VALUE) // overflow
                return 0;
            x = -x;
        }
        int res = 0;
        while(x != 0) {
            int digit = x % 10;
            if((Integer.MAX_VALUE - digit) / 10 < res) { // overflow
                return 0;
            }
            res = res * 10 + digit;
            x = x / 10;
        }
        if(sign == false)
            return -res;
        return res;
    }

[Leetcode] Largest Rectangle in Histogram

Given n non-negative integers representing the histogram's bar height where the width of each bar is 1, find the area of largest rectangle in the histogram.


Above is a histogram where width of each bar is 1, given height = [2,1,5,6,2,3].


The largest rectangle is shown in the shaded area, which has area = 10 unit.
For example,
Given height = [2,1,5,6,2,3],
return 10.

For the most naive method, we could start from one position i and expand to left and right as long as the height is height[left] >= height[i] or height[right] >= height[i]. This would give O(n^2) time complexity and would TLE. Actually, we have done many repeat work. For example, when we have check position i we calculate the furthest position it could reach to the left, then when we compute i+1, if height[i+1] <= height[i], we know for sure that i+1 could reach that point, too. We could use this to pre-calculate two array, each represent the furthest position to the left and right a given position could reach. The calculation of the array would utilize the result of the prior result so this would speed up the calculation. The amortized time complexity would be O(n).


    public int largestRectangleArea(int[] height) {
        int n = height.length;
        if(n == 0)
            return 0; // corner case
        int[] left = new int[n];
        int[] right = new int[n];
        left[0] = 0;
        for(int i = 1; i < n; i++) {
            int ind = i; 
            while(ind > 0 && height[ind - 1] >= height[i])
                ind = left[ind - 1];
            left[i] = ind;
        }
        right[n-1] = n-1;
        for(int i = n-2; i >= 0; i--) {
            int ind = i;
            while(ind < n-1 && height[ind + 1] >= height[i])
                ind = right[ind + 1];
            right[i] = ind;
        }
        int ma = Integer.MIN_VALUE;
        for(int i = 0; i < n; i++) {
            ma = Math.max(ma, height[i]*(right[i] - left[i] + 1));
        }
        return ma;
    }

Another solution is to use a stack, the details is available here http://www.geeksforgeeks.org/largest-rectangle-under-histogram/. The key idea here is that when a shorter histogram appear after a higher one, then the higher one would be turncate by this shorter one and we do not need to keep it any more.


    public int largestRectangleArea(int[] height) {
        int n = height.length;
        if(n == 0)
            return 0; // corner case
        Stack<Integer> stack = new Stack<Integer>();
        int i = 0;
        int ma = Integer.MIN_VALUE;
        while(i < n) {
            if(stack.isEmpty() || height[i] >= height[stack.peek()]) {
                stack.push(i);
                i++;
            }
            else {
                int tmp = stack.pop();
                int area = height[tmp]*(stack.isEmpty() == true ? i : (i - stack.peek() - 1));
                ma = Math.max(ma, area);
            }
        }
        while(stack.isEmpty() == false) {
            int tmp = stack.pop();
            int area = height[tmp]*(stack.isEmpty() == true ? i : (i - stack.peek() - 1));
            ma = Math.max(ma, area);
        }
        return ma;
    }

[Leetcode] Search Insert Position

Given a sorted array 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.
You may assume no duplicates in the array.
Here are few examples.
[1,3,5,6], 5 → 2
[1,3,5,6], 2 → 1
[1,3,5,6], 7 → 4
[1,3,5,6], 0 → 0

Basic binary search.

    public int searchInsert(int[] A, int target) {
        int n = A.length;
        int l = 0, r = n - 1;
        while(l <= r) {
            int mid = l + (r - l) / 2;
            if(A[mid] == target) {
                return mid;
            }
            else if(A[mid] > target) {
                r = mid - 1;
            }
            else 
                l = mid + 1;
        }
        return l;
    }

[Leetcode] Jump Game I & II

Given an array of non-negative integers, you are initially positioned at the first index of the array.
Each element in the array represents your maximum jump length at that position.
Determine if you are able to reach the last index.
For example:
A = [2,3,1,1,4], return true.
A = [3,2,1,0,4], return false.

We keep a right boundary represent the maximum index we could reach, when we sweep to the maximum index, we update this right boundary accordingly, whenever the right boundary gets to the last index, we know that we could get there, however, when we have reach the right boundary but we still not get the last index, we know that we could not reach the last index. The idea is some what like Breadth First Search.

    public boolean canJump(int[] A) {
        int n = A.length;
        if(n == 1)
            return true; // corner case
        int ma = 0;
        for(int i = 0; i <= ma; i++) {
            ma = Math.max(ma, i+A[i]); // extend the right boundary
            if(ma >= n-1)
                return true;
        }
        return false;
    }

Given an array of non-negative integers, you are initially positioned at the first index of the array.
Each element in the array represents your maximum jump length at that position.
Your goal is to reach the last index in the minimum number of jumps.
For example:
Given array A = [2,3,1,1,4]
The minimum number of jumps to reach the last index is 2. (Jump 1 step from index 0 to 1, then 3 steps to the last index.)

We use the similar idea of the above solution, this time we keep a window indicate the start position and end position, we sweep this window, and update the next step's end position and set next step's start position as end+1. Only when end position is not less than start position can we continue to jump, otherwise we have reach the maximum index we could reach. Once the end position where we could get exceeds the last index. We return the current step. This is just what Breadth First Search does.

    public int jump(int[] A) {
        int n = A.length;
        if(n == 1)
            return 0; // corner case
        int start = 0, end = 0;
        int nextS = end+1, nextE = end;
        int cnt = 1;
        while(nextE < n) {
            for(int i = start; i <= end; i++) { // according to the current step to update the next step where we could get
                nextE = Math.max(nextE, i+A[i]);
                if(nextE >= n - 1)
                    return cnt;
            }
            if(nextE < nextS) 
                break; // we could not continue to extend the boundary, this indicate that we could not reach the end
            start = nextS;
            end = nextE;
            nextS = end + 1;
            cnt++;
        }
        return cnt;
    }

[Leetcode] Clone Graph

Clone an undirected graph. Each node in the graph contains a label and a list of its neighbors.

OJ's undirected graph serialization: Nodes are labeled uniquely.
We use # as a separator for each node, and , as a separator for node label and each neighbor of the node. As an example, consider the serialized graph {0,1,2#1,2#2,2}.
The graph has a total of three nodes, and therefore contains three parts as separated by #.
  1. First node is labeled as 0. Connect node 0 to both nodes 1 and 2.
  2. Second node is labeled as 1. Connect node 1 to node 2.
  3. Third node is labeled as 2. Connect node 2 to node 2 (itself), thus forming a self-cycle.
Visually, the graph looks like the following:
       1
      / \
     /   \
    0 --- 2
         / \
         \_/

The key idea is to use a HashMap to record the mapping relationship of the original node and copied node. We start from on unvisited node, make a copy of it, and insert this mapping relation into the hashmap. Then we start to copy the neighbors, if we find a node that is not contained in the hashmap, then this indicates that we have another unvisited node, we recurse on this node. After the recursion, the node has had a copy, then we could add this copy to the neighbors. Be careful when the input is null since hashmap does not allow null to be inserted and this would be a corner case.


    public UndirectedGraphNode cloneGraph(UndirectedGraphNode node) {
        if(node == null)
            return null; // corner case
        HashMap<UndirectedGraphNode, UndirectedGraphNode> map = new HashMap<UndirectedGraphNode, UndirectedGraphNode>();
        dfs(node, map);
        return map.get(node);
    }
    
    private void dfs(UndirectedGraphNode node, HashMap<UndirectedGraphNode, UndirectedGraphNode> map) {
        UndirectedGraphNode newNode = new UndirectedGraphNode(node.label);
        map.put(node, newNode); // mark as visited
        for(UndirectedGraphNode un : node.neighbors) { // copy neighbors 
            if(map.containsKey(un) == false) // if neighbor not visited, there is no copyed node, recurse on this node
                dfs(un, map);
            newNode.neighbors.add(map.get(un));
        }
    }

[Leetcode] Best Time to Buy and Sell Stock

Say you have an array for which the ith element is the price of a given stock on day i.
If you were only permitted to complete at most one transaction (ie, buy one and sell one share of the stock), design an algorithm to find the maximum profit.

Keep the minimum value we could obtain to now, find the difference between the current value with the minimum, update the maximum if necessary.


    public int maxProfit(int[] prices) {
        int res = 0;
        int n = prices.length;
        if(n == 0)
            return 0;
        int mi = Integer.MAX_VALUE;
        for(int i = 0; i < n; i++) {
            mi = Math.min(mi, prices[i]);
            res = Math.max(res, prices[i] - mi);
        }
        return res;
    }

[Leetcode] Longest Palindromic Substring

Given a string S, find the longest palindromic substring in S. You may assume that the maximum length of S is 1000, and there exists one unique longest palindromic substring.

A very classical problem. The most naive way is to enumerate all substring and then check if each string is a valid palindrome. This would give O(n^3) time complexity. A better way is to start from a character as the center and expand to left and right to see the longest palindrome we could obtain. We need to check two cases: both even length and odd length. This would give O(n^2) time complexity.

    public String longestPalindrome(String s) {
        int n = s.length();
        if(n == 0)
            return s; // corner case
        int ma = 0;
        int mai = 0, maj = 0;
        for(int i = 0; i < n; i++) { // case 1 odd
            int left = i, right = i;
            while(left >= 0 && right < n && s.charAt(left) == s.charAt(right)) {
                left--; right++;
            }
            if(ma < right - left - 1) {
                ma = right - left - 1;
                mai = left + 1;
                maj = right - 1;
            }
        }
        for(int i = 0; i < n-1; i++) { // case 2 even
            int left = i, right = i+1;
            while(left >= 0 && right < n && s.charAt(left) == s.charAt(right)) {
                left--; right++;
            }
            if(ma < right - left - 1) {
                ma = right - left - 1;
                mai = left + 1;
                maj = right - 1;
            }
        }
        return s.substring(mai, maj+1);
    }

Another way is to use DP to solve this problem. However, the time complexity is still O(n^2) and space complexity is O(n^2), too. The steps are as follow:
  • We use dp[i][j] to represent whether s[i...j] is a valid palindrome or not.
    1. if i == j, then dp[i][j] = true.
    2. if i+1 == j and s[i] == s[j], dp[i][j] = true.
    3. otherwise, only if dp[i+1][j-1] == true and s[i] == s[j], dp[i][j] = true.
  • During the process, whenever we find a new valid palindrome, we update the current max and record the index

    public String longestPalindrome(String s) {
        int n = s.length();
        if(n == 0)
            return s; // corner case
        boolean[][] dp = new boolean[n][n];
        int ma = 0;
        int mai = 0, maj = 0; // index of the longest palindrome string
        for(int i = n-1; i >= 0; i--) {
            for(int j = i; j < n; j++) {
                if(i == j) { // case 1
                    dp[i][j] = true;
                    if(ma < j-i+1) {
                        ma = j-i+1;
                        mai = i; maj = j;
                    }
                }
                else if(i+1 == j) { // case 2
                    if(s.charAt(i) == s.charAt(j)) {
                        dp[i][j] = true;
                        if(ma < j-i+1) {
                            ma = j-i+1;
                            mai = i; maj = j;
                        }
                    }
                    else
                        dp[i][j] = false;
                }
                else { // case 3
                    if(s.charAt(i) == s.charAt(j) && dp[i+1][j-1] == true) {
                        dp[i][j] = true;
                        if(ma < j-i+1) {
                            ma = j-i+1;
                            mai = i; maj = j;
                        }
                    }
                    else
                        dp[i][j] = false;
                }
            }
        }
        return s.substring(mai, maj+1);
    }

[Leetcode] Merge Interval

Given a collection of intervals, merge all overlapping intervals.
For example,
Given [1,3],[2,6],[8,10],[15,18],
return [1,6],[8,10],[15,18].

Write a comparator to sort the intervals according to their start time. Then from the first interval, we do following:
  1. initialize the current merged interval using the first interval
  2. if the current interval intersect with the current merged interval, then we update the endTime of the current interval
  3. otherwise we insert the current merged interval to the result, and update the current merged interval using the current interval
In all case, their would not have the situation where current interval's start time is lower than current merged interval's start time, since we have sort the list according to the start time. Be careful with the final state, the last merged interval is not added to the result yet when the for loop terminate.

    public class myComparator implements Comparator<Interval> {
        public int compare(Interval i1, Interval i2) {
            return i1.start - i2.start;
        }
    }
    public List<Interval> merge(List<Interval> intervals) {
        if(intervals.size() == 0)
            return intervals;
        List<Interval> res = new ArrayList<Interval>();
        Collections.sort(intervals, new myComparator());
        int startTime = intervals.get(0).start, endTime = intervals.get(0).end;
        for(Interval i : intervals) {
            if(i.start > endTime) {
                Interval interval = new Interval(startTime, endTime);
                res.add(interval);
                startTime = i.start;
                endTime = i.end;
            }
            else {
                endTime = Math.max(endTime, i.end);
            }
        }
        Interval interval = new Interval(startTime, endTime);
        res.add(interval);
        return res;
    }

[Leetcode] Insert Interval

Given a set of non-overlapping intervals, insert a new interval into the intervals (merge if necessary).
You may assume that the intervals were initially sorted according to their start times.
Example 1:
Given intervals [1,3],[6,9], insert and merge [2,5] in as [1,5],[6,9].
Example 2:
Given [1,2],[3,5],[6,7],[8,10],[12,16], insert and merge [4,9] in as [1,2],[3,10],[12,16].
This is because the new interval [4,9] overlaps with [3,5],[6,7],[8,10].

When we meet an interval intersect with the current merged interval, we update the start and end accordingly. The initial state of the merged interval is the start and end of the new interval. A corner case is that the interval is inserted into the end of the list or it merged all interval in the list. In this case we need to check if we have ever insert the merged interval into the list.


    public List<Interval> insert(List<Interval> intervals, Interval newInterval) {
        List<Interval> res = new ArrayList<Interval>();
        int startTime = newInterval.start, endTime = newInterval.end;
        boolean merged = false;
        for(Interval i : intervals) {
            if(i.end < startTime) {
                res.add(i);
            }
            else if(i.start > endTime) {
                if(merged == false) {
                    Interval interval = new Interval(startTime, endTime);
                    res.add(interval);
                    merged = true;
                }
                res.add(i);
            }
            else {
                startTime = Math.min(startTime, i.start);
                endTime = Math.max(endTime, i.end);
            }
        }
        if(merged == false) {
            Interval interval = new Interval(startTime, endTime);
            res.add(interval);
            merged = true;
        }
        return res;
    }

2014年11月29日星期六

[Leetcode] Add Binary

Given two binary strings, return their sum (also a binary string).
For example,
a = "11"
b = "1"
Return "100".

Similar to the problem Plus One. Time complexity is O(n) and we ignore the required return value the space complexity is O(1).


    public String addBinary(String a, String b) {
        if(a.length() < b.length()) {
            return addBinary(b, a);
        }
        StringBuffer sb = new StringBuffer();
        int ind1 = a.length() - 1, ind2 = b.length() - 1;
        int carry = 0;
        while(ind2 >= 0) {
            int num1 = a.charAt(ind1) - '0';
            int num2 = b.charAt(ind2) - '0';
            int res = num1 + num2 + carry;
            carry = res / 2;
            res = res % 2;
            ind1--; ind2--;
            sb.append(res);
        }
        while(ind1 >= 0) {
            int num1 = a.charAt(ind1) - '0';
            int res = num1 + carry;
            carry = res / 2;
            res = res % 2;
            ind1--;
            sb.append(res);
        }
        if(carry != 0)
            sb.append(carry);
        sb = sb.reverse();
        return sb.toString();
    }

[Leetcode] String to Integer (atoi)

Implement atoi to convert a string to an integer.
Hint: Carefully consider all possible input cases. If you want a challenge, please do not see below and ask yourself what are the possible input cases.
Notes: It is intended for this problem to be specified vaguely (ie, no given input specs). You are responsible to gather all the input requirements up front.

Requirements for atoi: The function first discards as many whitespace characters as necessary until the first non-whitespace character is found. Then, starting from this character, takes an optional initial plus or minus sign followed by as many numerical digits as possible, and interprets them as a numerical value.
The string can contain additional characters after those that form the integral number, which are ignored and have no effect on the behavior of this function.
If the first sequence of non-whitespace characters in str is not a valid integral number, or if no such sequence exists because either str is empty or it contains only whitespace characters, no conversion is performed.
If no valid conversion could be performed, a zero value is returned. If the correct value is out of the range of representable values, INT_MAX (2147483647) or INT_MIN (-2147483648) is returned.

First, we trim the leading and tailing spaces. Then, we read the first character to see if it is '-' or '+' to determine the sign. After that, we check each character, if it is not valid, we return the current result, other wise, we check to see if it would overflow or not. In my implementation, I check if it would overflow separately.


    public int atoi(String str) {
        str = str.trim(); // handle spaces
        if(str.length() == 0)
            return 0;
        int res = 0;
        if(str.charAt(0) == '-') { // negative integer
            str = str.substring(1);
            for(int i = 0; i < str.length(); i++) {
                if(str.charAt(i) < '0' || str.charAt(i) > '9') // invalid character
                    break;
                int num = str.charAt(i) - '0';
                if((Integer.MIN_VALUE + num) / 10 > res) // overflow
                    return Integer.MIN_VALUE;
                else
                    res = res * 10 - num;
            }
        }
        else {
            if(str.charAt(0) == '+')
                str = str.substring(1);
            for(int i = 0; i < str.length(); i++) {
                if(str.charAt(i) < '0' || str.charAt(i) > '9') // invalid character
                    break;
                int num = str.charAt(i) - '0';
                if((Integer.MAX_VALUE - num) / 10 < res) // overflow
                    return Integer.MAX_VALUE;
                else
                    res = res * 10 + num;
            }
        }
        return res;
    }

[Leetcode] Permutations I & II

Given a collection of numbers, return all possible permutations.
For example,
[1,2,3] have the following permutations:
[1,2,3], [1,3,2], [2,1,3], [2,3,1], [3,1,2], and [3,2,1].

The most basic form of permutation. We could calculate the permutation recursively. At each step, we choose the possible digit could be here, and append the permutation of the remaining numbers to the current state. I swap the order of the numbers in the array to get all possible permutations.

    public List<List<Integer>> permute(int[] num) {
        List<List<Integer>> res = new ArrayList<List<Integer>>();
        if(num.length == 0)
            return res;
        dfs(num, 0, res);
        return res;
    }
    
    private void dfs(int[] num, int ind, List<List<Integer>> res) {
        if(ind == num.length) {
            List<Integer> cur = new ArrayList<Integer>();
            for(int i = 0; i < num.length; i++)
                cur.add(num[i]);
            res.add(cur);
        }
        else {
            for(int i = ind; i < num.length; i++) {
                int swap = num[ind];
                num[ind] = num[i];
                num[i] = swap;
                dfs(num, ind+1, res);
                swap = num[ind];
                num[ind] = num[i];
                num[i] = swap;
            }
        }
    }
The time complexity would be O(n!) and space complexity would be O(n) if we do not take the result into consideration.

Given a collection of numbers that might contain duplicates, return all possible unique permutations.
For example,
[1,1,2] have the following unique permutations:
[1,1,2], [1,2,1], and [2,1,1].

When duplicates are introduced into the problem, it is always more difficult to handle since the result may contain duplicates too if we stick to the original method. At first, I tired to use some technique used in subsets II or combination sum II where skip the duplicates. However, I quickly found that since we are changing the order of the original array so this method fails. At last, I used a hashset to record which elements have been used and the duplicates are skipped.

    public List<List<Integer>> permuteUnique(int[] num) {
        List<List<Integer>> res = new ArrayList<List<Integer>>();
        if(num.length == 0)
            return res;
        dfs(num, 0, res);
        return res;
    }
    
    private void dfs(int[] num, int ind, List<List<Integer>> res) {
        if(ind == num.length) {
            List<Integer> cur = new ArrayList<Integer>();
            for(int i = 0; i < num.length; i++)
                cur.add(num[i]);
            res.add(cur);
        }
        else {
            HashSet<Integer> set = new HashSet<Integer>();
            for(int i = ind; i < num.length; i++) {
                if(set.contains(num[i]) == true) 
                    continue;
                int swap = num[ind];
                num[ind] = num[i];
                num[i] = swap;
                dfs(num, ind+1, res);
                swap = num[ind];
                num[ind] = num[i];
                num[i] = swap;
                set.add(num[i]);
            }
        }
    }
The time complexity is still O(n!) and space complexity is O(n).

2014年11月28日星期五

[Leetcode] Single Number I & II

Given an array of integers, every element appears twice except for one. Find that single one.
Note:
Your algorithm should have a linear runtime complexity. Could you implement it without using extra memory?

    public int singleNumber(int[] A) {
        int res = 0;
        for(int i = 0; i < A.length; i++)
            res = res ^ A[i];
        return res;
    }

Given an array of integers, every element appears three times except for one. Find that single one.
Note:
Your algorithm should have a linear runtime complexity. Could you implement it without using extra memory?

    public int singleNumber(int[] A) {
        int[] bits = new int[32];
        for(int i = 0; i < A.length; i++) {
            for(int j = 0; j < 32; j++) {
                if((A[i] & (1 << j)) != 0)
                    bits[j]++;
            }
        }
        int res = 0;
        for(int i = 0 ; i < 32; i++) {
            bits[i] = bits[i] % 3;
            if(bits[i] != 0)
                res = res + (1 << i);
        }
        return res;
    }

[Leetcode] Candy

There are N children standing in a line. Each child is assigned a rating value.
You are giving candies to these children subjected to the following requirements:
  • Each child must have at least one candy.
  • Children with a higher rating get more candies than their neighbors.
What is the minimum candies you must give?

Use two pass to get the minimum number of candy we give to each children. In the first pass, we scan from left to right, when ever rating[i] is greater than rating[i-1], we assign candy[i-1] + 1 to candy[i] meaning i must at least get one more candy than i-1. Otherwise we give only 1 candy. After the first sweep, we have valid the condition on left side of each child. Then on the second pass, we scan from right to left, when we find rating[i] > rating[i+1], we adjust what i get to the maximum number between candy[i] and candy[i+1]+1. After the second pass, we get what we the minimum number of candy we give to each children.

    public int candy(int[] ratings) {
        int n = ratings.length;
        if(n == 0)
            return 0; // corner case
        int[] candy = new int[n];
        candy[0] = 1; // base case
        for(int i = 1; i < n; i++) {
            candy[i] = (ratings[i] > ratings[i-1]) ? candy[i-1] + 1 : 1;
        }
        for(int i = n-2; i >= 0; i--) {
            if(ratings[i] > ratings[i+1])
                candy[i] = Math.max(candy[i], candy[i+1] + 1);
        }
        int res = 0;
        for(int i = 0; i < n; i++)
            res += candy[i];
        return res;
    }

[Leetcode] Gas Station

There are N gas stations along a circular route, where the amount of gas at station i is gas[i].
You have a car with an unlimited gas tank and it costs cost[i] of gas to travel from station i to its next station (i+1). You begin the journey with an empty tank at one of the gas stations.
Return the starting gas station's index if you can travel around the circuit once, otherwise return -1.
Note:
The solution is guaranteed to be unique.

The most naive method is to enumerate each position and loop the entire array to see if this position is valid or not. The time complexity is O(n^2). Actually we could use linear method to solve this problem since there exist many "waste check".

Image we start from some point say i, and we count the gas - cost from this point to j and find that we get a residual with negative, this means that we could not start from position and get j. In the naive method, we would move to i+1 and try again. However, we could skip to j+1 since i+1 would still give a negative residual. We would utilize this to speed up the algorithm.
  1. First check if the total gas is larger than total cost, if not, we return -1.
  2. If we start from some point i and reach to the end of the array with residual, this means this is the solution, since the solution is guaranteed to be unique.
  3. If at some point j, we get negative residual, we skip i...j, start from j+1.
Why could we say that from point i, if we could reach to the end of the array, then this is the solution. Since if there is another point i' behind i (there is no solution in front of i) could reach to the end, but the solution is guarantee to be unique, then i and i' must be the same. And we have check that there could exist an solution.
    public int canCompleteCircuit(int[] gas, int[] cost) {
        int n = gas.length;
        int[] dif = new int[n]; // store the difference of gas and cost
        int res = 0;
        for(int i = 0; i < n; i++) {
            dif[i] = gas[i] - cost[i];
            res += dif[i];
        }
        if(res < 0)
            return -1; // could not run the whole circle
        int ind1 = 0, ind2 = 0;
        while(ind1 < n) {
            int temp = 0;
            while(ind2 < n && temp >= 0) {
                temp += dif[ind2];
                ind2++;
            }
            if(temp < 0)
                ind1 = ind2; // have not finish the circle, could not reach the end
            else
                return ind1; // from here we could reach the end and since the solution is unique, this would be the solution
        }
        return -1;
    }

[Leetcode] Set Matrix Zeroes

Given a m x n matrix, if an element is 0, set its entire row and column to 0. Do it in place.
Follow up: Did you use extra space?
A straight forward solution using O(mn) space is probably a bad idea.
A simple improvement uses O(m + n) space, but still not the best solution.
Could you devise a constant space solution?

A naive way is to use extra array to record whether the row or the column should be set to zero or not. We could use the first column and first row of the matrix to do so. The time complexity would be O(mn) and space complexity would be O(1).


    public void setZeroes(int[][] matrix) {
        int m = matrix.length;
        if(m == 0)
            return; // corner case
        int n = matrix[0].length;
        boolean row = false, col = false; // check the first row and column
        for(int i = 0; i < m; i++) {
            if(matrix[i][0] == 0)
                col = true;
        }
        for(int i = 0; i < n; i++) {
            if(matrix[0][i] == 0)
                row = true;
        }
        // check each row and column and store the information int the first row and column
        for(int i = 1; i < m; i++) {
            for(int j = 1; j < n; j++) {
                if(matrix[i][j] == 0) {
                    matrix[0][j] = 0;
                    matrix[i][0] = 0;
                }
            }
        }
        // set the matrix
        for(int i = 1; i < m; i++) {
            if(matrix[i][0] == 0) {
                for(int j = 0; j < n; j++)
                    matrix[i][j] = 0;
            }
        }
        for(int i = 1; i < n; i++) {
            if(matrix[0][i] == 0) {
                for(int j = 0; j < m; j++)
                    matrix[j][i] = 0;
            }
        }
        if(row == true) {
            for(int i = 0; i < n; i++)
                matrix[0][i] = 0;
        }
        if(col == true) {
            for(int i = 0; i < m; i++) 
                matrix[i][0] = 0;
        }
    }

[Leetcode] Gray Code

The gray code is a binary numeral system where two successive values differ in only one bit.
Given a non-negative integer n representing the total number of bits in the code, print the sequence of gray code. A gray code sequence must begin with 0.
For example, given n = 2, return [0,1,3,2]. Its gray code sequence is:
00 - 0
01 - 1
11 - 3
10 - 2
Note:
For a given n, a gray code sequence is not uniquely defined.
For example, [0,2,3,1] is also a valid gray code sequence according to the above definition.

We could obtain the n+1th solution from what we have from nth solution. Since nth solution has already satisfy the property of gray code.
  1. We get a copy of the nth solution.
  2. We reverse the copy, now the copy still satisfy the gray code.
  3. For each reversed element, we add 2^n to it, thus there will be a leading 1 compared to the original list.
  4. Append this list to the original, and we have obtain the n+1th solution.
After the reversion, the first element of the copy list would be the same with the last of the original element. In order to satisfy the gray code property, we add a leading 1 to all of the elements in the copy list. This would not break the gray code property in the copy list, and would make sure the first element in the copy list differ one bits from the last one in the original list. Thus the gray code property is maintained.
    public List<Integer> grayCode(int n) {
        List<Integer> res = new ArrayList<Integer>();
        res.add(0); // base case
        for(int i = 0; i < n; i++) {
            int base = (1 << i);
            int m = res.size();
            for(int j = m-1; j >= 0; j--) {
                res.add(res.get(j) + base);
            }
        }
        return res;
    }

[Leetcode] Rotate Image

You are given an n x n 2D matrix representing an image.
Rotate the image by 90 degrees (clockwise).
Follow up:
Could you do this in-place?

Two method to do so. One is to swap according to the diagonal and then swap according to the middle row.

    public void rotate(int[][] matrix) {
        int m = matrix.length;
        if(m == 0)
            return; // corner case
        int n = matrix[0].length;
        // swap according to the diag
        for(int i = 0; i < m; i++) {
            for(int j = 0; j < n - i - 1; j++) {
                int temp = matrix[i][j];
                matrix[i][j] = matrix[n-1-j][m-1-i];
                matrix[n-1-j][m-1-i] = temp;
            }
        }
        // swap accoding to the middle
        int half = m / 2;
        for(int i = 0; i < half; i++) {
            for(int j = 0; j < n; j++) {
                int temp = matrix[i][j];
                matrix[i][j] = matrix[m-i-1][j];
                matrix[m-i-1][j] = temp;
            }
        }
    }

Another way is to define four subarea and then swap them. If n is even then the subarea would be a square and if n is odd the subarea would be a rectangle with length and width differ by one.

    public void rotate(int[][] matrix) {
        int m = matrix.length;
        if(m == 0)
            return; // corner case
        int n = matrix[0].length;
        int x = m / 2;
        int y = (m+1) / 2; // subarea to be rotate
        for(int i = 0; i < x; i++) {
            for(int j = 0; j < y; j++) {
                int temp = matrix[i][j];
                matrix[i][j] = matrix[m-1-j][i];
                matrix[m-1-j][i] = matrix[n-1-i][m-1-j];
                matrix[n-1-i][m-1-j] = matrix[j][n-1-i];
                matrix[j][n-1-i] = temp;
            }
        }
    }

2014年11月27日星期四

[Leetcode] Trapping Rain Water

Given n non-negative integers representing an elevation map where the width of each bar is 1, compute how much water it is able to trap after raining.
For example,
Given [0,1,0,2,1,0,1,3,2,1,2,1], return 6.


The above elevation map is represented by array [0,1,0,2,1,0,1,3,2,1,2,1]. In this case, 6 units of rain water (blue section) are being trapped. Thanks Marcos for contributing this image!

On any given position, the water it could hold is determined by the minimum height of the highest elevation on its both side. For example, [1, 0, 2, 3], the water could be hold at '0' is determined by the highest elevation on its left which is 1 and highest elevation on its right which is 3. We need to choose the minimum of this two value, given 1.


    public int trap(int[] A) {
        int n = A.length;
        if(n == 0)
            return 0; // corner case
        int[] left = new int[n]; // highest on left
        int[] right = new int[n]; // highest on right
        left[0] = A[0];
        int ma = A[0];
        for(int i = 1; i < n; i++) {
            ma = Math.max(ma, A[i]);
            left[i] = ma;
        }
        right[n-1] = A[n-1];
        ma = A[n-1];
        for(int i = n-2; i >= 0; i--) {
            ma = Math.max(ma, A[i]);
            right[i] = ma;
        }
        int res = 0;
        for(int i = 0; i < n; i++) {
            res = res + Math.min(left[i], right[i]) - A[i];
        }
        return res;
    }

The time complexity is O(n) and the space complexity is O(n).
A follow of this problem is given that at a point where the elevation is zero, it is leaking water and could not hold any water there. In this case, we need just to modify ma to 0 in this case. Which give the following code.
 /* A kind of follow up of Trapping Raining Water,
  * where the elevation with 0 is leaking water and
  * could not hold water
  */
    public static int trap(int[] A) {
        int n = A.length;
        if(n == 0)
            return 0; // corner case
        int[] left = new int[n]; // highest on left
        int[] right = new int[n]; // highest on right
        left[0] = A[0];
        int ma = A[0];
        for(int i = 1; i < n; i++) {
            ma = Math.max(ma, A[i]);
            ma = A[i] == 0 ? 0 : ma;
            left[i] = ma;
        }
        right[n-1] = A[n-1];
        ma = A[n-1];
        for(int i = n-2; i >= 0; i--) {
            ma = Math.max(ma, A[i]);
            ma = A[i] == 0 ? 0 : ma;
            right[i] = ma;
        }
        int res = 0;
        for(int i = 0; i < n; i++) {
            res = res + Math.min(left[i], right[i]) - A[i];
        }
        return res;
    }

[Leetcode] Intersection of Two Linked Lists

Write a program to find the node at which the intersection of two singly linked lists begins.

For example, the following two linked lists:
A:          a1 → a2
                   ↘
                     c1 → c2 → c3
                   ↗            
B:     b1 → b2 → b3
begin to intersect at node c1.

Notes:
  • If the two linked lists have no intersection at all, return null.
  • The linked lists must retain their original structure after the function returns.
  • You may assume there are no cycles anywhere in the entire linked structure.
  • Your code should preferably run in O(n) time and use only O(1) memory.

The first method is like find the LCA of two nodes with parent pointer. We make the two nodes have the same "depth" and then look forward to see if there is a common node.

    public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
        if(headA == null || headB == null)
            return null; // corner case
        ListNode tempA = headA, tempB = headB;
        int lenA = 0, lenB = 0;
        // find the lenght of the two list
        while(tempA != null) {
            lenA++;
            tempA = tempA.next;
        }
        while(tempB != null) {
            lenB++;
            tempB = tempB.next;
        }
        tempA = headA;
        tempB = headB;
        // turncate the longer list
        if(lenA > lenB) {
            while(lenA > lenB) {
                lenA--;
                tempA = tempA.next;
            }
        }
        else if(lenA < lenB) {
            while(lenA < lenB) {
                lenB--;
                tempB = tempB.next;
            }
        }
        // find the first common listnode in the two list if exist
        while(tempA != null && tempB != null) {
            if(tempA == tempB)
                return tempA;
            tempA = tempA.next;
            tempB = tempB.next;
        }
        return null;
    }

The time complexity is O(m+n) and space complexity is O(1).
Another method is to create a cycle by hand. We link A's tail to its head, then if there indeed is a intersection node, there would be a cycle and the node would be the start point where the cycle begin. So we could use the same method for the single linked list. Remember to recover the two list to their original structure. The time complexity and space complexity is the same with the prior one.

    public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
        if(headA == null || headB == null)
            return null; // corner case
        ListNode tail = headA;
        // find the tail of A and link it to head
        while(tail.next != null)
            tail = tail.next;
        tail.next = headA;
        // B is now a single linked list with circle or not
        if(headB == null || headB.next == null) {
            tail.next = null;
            return null;
        }
        ListNode slow = headB, fast = headB;
        while(fast != null && fast.next != null) {
            slow = slow.next;
            fast = fast.next.next;
            if(slow == fast)
                break;
        }
        // check if there is circle
        if(fast == null || fast.next == null) {
            tail.next = null;
            return null;
        }
        fast = headB;
        while(slow != fast) {
            fast = fast.next;
            slow = slow.next;
        } 
        // recover to original structure
        tail.next = null;
        return slow;
    }

[Leetcode] Valid Sudoku

Determine if a Sudoku is valid, according to: Sudoku Puzzles - The Rules.
The Sudoku board could be partially filled, where empty cells are filled with the character '.'.


A partially filled sudoku which is valid.
Note:
A valid Sudoku board (partially filled) is not necessarily solvable. Only the filled cells need to be validated.

Simple implementation problem. For each position on the board (x, y), we check:
  1. the row x
  2. the column y
  3. the square where (x, y) located in, it is determined by (x/3)*3 ~ (x/3+1)*3 and (y/3)*3 ~(y/3+1)*3
The over all time complexity is O(n^3) and space complexity is O(1).

    public boolean isValidSudoku(char[][] board) {
        int m = board.length;
        int n = board[0].length;
        for(int i = 0; i < m; i++) {
            for(int j = 0; j < n; j++) {
                if(!check(board, i, j))
                    return false;
            }
        }
        return true;
    }
    
    private boolean check(char[][] board, int x, int y) {
        int m = board.length;
        int n = board[0].length;
        if(board[x][y] == '.')
            return true;
        // check row
        for(int i = 0; i < n; i++) {
            if(i != y && board[x][i] == board[x][y])
                return false;
        }
        // check column
        for(int i = 0; i < m; i++) {
            if(i != x && board[i][y] == board[x][y])
                return false;
        }
        // check 3*3 square
        for(int i = (x/3)*3; i < (x/3+1)*3; i++) {
            for(int j = (y/3)*3; j < (y/3+1)*3; j++) {
                if(i != x && j != y && board[i][j] == board[x][y])
                    return false;
            }
        }
        return true;
    }

Another method is to use a hashset or an array to hold the element we have meet in the row/column/square we are examining. This would reduce the time complexity to O(n^2) with space complexity to O(n).

public class Solution {
    public boolean isValidSudoku(char[][] board) {
        int m = board.length;
        int n = board[0].length;
        HashSet<Character> set = new HashSet<Character>();
        // check row
        for(int i = 0; i < m; i++) {
            set.clear();
            for(int j = 0; j < n; j++) {
                if(board[i][j] != '.') {
                    if(set.contains(board[i][j]) == true)
                        return false;
                    else
                        set.add(board[i][j]);
                }
            }
        }
        // check column
        for(int i = 0; i < n; i++) {
            set.clear();
            for(int j = 0; j < m; j++) {
                if(board[j][i] != '.') {
                    if(set.contains(board[j][i]) == true)
                        return false;
                    else
                        set.add(board[j][i]);
                }
            }
        }
        // check square
        for(int i = 0; i < m; i += 3) {
            for(int j = 0; j < n; j += 3) {
                set.clear();
                for(int x = (i/3)*3; x < (i/3+1)*3; x++) {
                    for(int y = (j/3)*3; y < (j/3+1)*3; y++) {
                        if(board[x][y] != '.') {
                            if(set.contains(board[x][y]) == true)
                                return false;
                            else
                                set.add(board[x][y]);
                        }
                    }
                }
            }
        }
        return true;
    }
}

[Leetcode] Plus One

Given a non-negative number represented as an array of digits, plus one to the number.
The digits are stored such that the most significant digit is at the head of the list.


    public int[] plusOne(int[] digits) {
        int n = digits.length;
        if(n == 0)
            return digits; // corner case
        int carry = 1;
        // simulate the plus
        for(int i = n-1; i >= 0; i--) {
            digits[i] = digits[i] + carry;
            carry = digits[i] / 10;
            digits[i] = digits[i] % 10;
        }
        // have one carry at last need to resize the array
        if(carry != 0) {
            int[] res = new int[n+1];
            for(int i = n; i >= 1; i--) {
                res[i] = digits[i-1];
            }
            res[0] = carry;
            digits = res;
        }
        return digits;
    }

2014年11月25日星期二

[Leetcode] Binary Tree Postorder Traversal II

The follow up for the first post about postorder traversal.

In the first post, I introduced how to use Morris iteration to implement postorder traversal of a given binary tree. However it is too complicate and not easy to code during an interview. Here, I introduce another two ways to do a postorder traversal iteratively.

The first method is to use two stacks.
  1. Push the root node to the first stack.
  2. Pop a node from the first stack, and push it to the second stack.
  3. Then push its left child followed by its right child to the first stack.
  4. Repeat step 2) and 3) until the first stack is empty.
  5. Once done, the second stack would have all the nodes ready to be traversed in post-order. Pop off the nodes from the second stack one by one and you’re done.


    
    List<Integer> list = new ArrayList<Integer>();
    
    public List<Integer> postorderTraversal(TreeNode root) {
        if(root == null)
   return list; // corner case when root is null
  
  Stack<TreeNode> stack1 = new Stack<TreeNode>();
  Stack<TreeNode> stack2 = new Stack<TreeNode>();
  stack1.push(root);
  while(stack1.size() != 0) {
   TreeNode cur = stack1.pop();
   if(cur.left != null)
    stack1.push(cur.left);
   if(cur.right != null)
    stack1.push(cur.right);
   stack2.push(cur);
  }
  while(stack2.size() != 0) 
   list.add(stack2.pop().val);
  return list;
    }

Another way is just use one stack, and use a node to record the prior visited node. According to the type of the current node(leaf, nonleaf with only left or right child, nonleaf with both children) to perform differently.

  1. Each time we pick the top of the stack and check
    • if it is a leaf node, then print it
    • if it is a node with only left child, if pre = left child, then we know we have finish visiting the left child, print it; otherwise, the left child has not been visited yet, we push the current node pack and push the left child into stack
    • if it is a node with only right child, similar with the prior one
    • if it is a node with both children
      • if pre = left child, we know we finish the left child and we need to continue with right child, so push itself and right child into stack
      • if pre = right child, we know we have finished both child, print it
      • else we have not visited any child, we push itself and left child into stack
  2. Update the pre node when we print something out



 public static void postorder(TreeNode root) {
  if(root == null)
   return ; // corner case when root is null
  
  Stack<TreeNode> stack = new Stack<TreeNode>();
  TreeNode pre = null, cur = null;
  stack.push(root);
  while(stack.size() != 0) {
   cur = stack.pop();
   if(cur.left == null && cur.right == null) {
    System.out.println(cur.val);
    pre = cur;
   }
   else if(cur.left != null && cur.right == null) {
    if(pre == cur.left) {
     System.out.println(cur.val);
     pre = cur;
    }
    else {
     stack.push(cur);
     stack.push(cur.left);
    }
   }
   else if(cur.left == null && cur.right != null) {
    if(pre == cur.right) {
     System.out.println(cur.val);
     pre = cur;
    }
    else {
     stack.push(cur);
     stack.push(cur.right);
    }
   }
   else {
    if(pre == cur.left) {
     stack.push(cur);
     stack.push(cur.right);
    }
    else if(pre == cur.right) {
     System.out.println(cur.val);
     pre = cur;
    }
    else {
     stack.push(cur);
     stack.push(cur.left);
    }
   }
  }
 }

My implementation is somehow redundant. Here is a better implementation but a little harder to understand.http://leetcode.com/2010/10/binary-tree-post-order-traversal.html

2014年11月24日星期一

[Leetcode] Permutation Sequence

The set [1,2,3,…,n] contains a total of n! unique permutations.
By listing and labeling all of the permutations in order,
We get the following sequence (ie, for n = 3):
  1. "123"
  2. "132"
  3. "213"
  4. "231"
  5. "312"
  6. "321"
Given n and k, return the kth permutation sequence.
Note: Given n will be between 1 and 9 inclusive.
In order to handle this problem, we use some mathematical method and recursively compute the digit on each position.

We have a list of integer from 1...N where we could choice from. Since the permutation would use up all the integers in this list. When list has only 1 elements left, then this means we have pick out n-1. And what we need to do is just pick out this element, then we are done.

What if there are multiple numbers in the list? We need to determine which to choose by the number k.  If we have m elements in the list, then we now that there are m! permutation, and if we pick one, then there are (m-1)! permutation, meaning each leading elements would appear (m-1)! times. That is we choose list[k/(m-1)!] as this step choice, and we recursive on the m-1 with k = k%(m-1) (since we have determine the first element, there are already k/(m-1)!*(m-1)! elements less than us). However, pay great attention to k%(m-1) == 0, this means we actually get the last permutation in the bunch leading with k/(m-1)! - 1, this is a corner case and should be handle separately, since it is the last one, after picking the leading digit, we could just appending all the digits still in list now reversely.

Let's go over some simple examples.

Suppose n = 4 and k = 4.

  1. step size (m-1)! = 6. In the first step, we choose 4 / 6 = 0th element in the list which is 1. And recursive with n = 3 and k = 4 % 6 = 4, the list now is 2 3 4;
  2. step size (m-1)! = 2. In the second step, we choose 4 / 2 = 2nd element, however notice that 4 % 2 = 0. So we actually want the last permutation leading with the 1st element in list which is 3. That is 3 4 2, we append it to the result and return.
  3. Finally, we get 1 3 4 2.
Here is another example.

Suppose n = 4 and k = 3.

  1.  step size (m-1)! = 6. In the first step, we choose 4 / 6 = 0th element in the list which is 1. And recursive with n = 3 and k = 4 % 6 = 4, the list now is 2 3 4;
  2. step size (m-1)! = 2. In the second step, we choose 3 / 2 = 1st element which is 3. And recursive with n = 2 and k = 3 % 2 = 1, the list now is 2 4;
  3. step size (m-1)! = 1. In the third step, we choose 1 / 1 = 1st element. However 1 % 1 = 0, so we choose 0th element which is 2 and appending the remaining ones reversely. 
  4. Finally we get 1 3 2 4.


public class Solution {
    List<Integer> list = new ArrayList<Integer>();
    public String getPermutation(int n, int k) {
        for(int i = 1; i <= n; i++) {
            list.add(i);
        }
        return dfs("", n, k);
    }
    
    private String dfs(String cur, int n, int k) {
        if(n == 1) {
            return cur + list.get(0); // base case, the last element
        }
        else {
            int num = 1;
            for(int i = 1; i < n; i++)
                num *= i; // step size for this step
            int index = k / num;
            int residual = k % num;
            if(residual != 0) {
                cur = cur + list.get(index);
                list.remove(index);
                return dfs(cur, n-1, residual);
            }
            else {
                cur = cur + list.get(index-1);
                list.remove(index-1);
                for(int i = list.size() - 1; i >= 0; i--) {
                    cur = cur + list.get(i);
                }
                return cur;
            }
        }
    }
}

2014年11月23日星期日

[Leetcode] Remove Element

Given an array and a value, remove all instances of that value in place and return the new length.
The order of elements can be changed. It doesn't matter what you leave beyond the new length.
Simple problem. Since you do not need to hold the order of the original array.
    public int removeElement(int[] A, int elem) {
        if(A.length == 0) 
            return 0;
        int p1= 0, p2 = A.length - 1;
        while(p1 <= p2) {
            if(A[p1] == elem) {
                A[p1] = A[p2];
                p2--;
            }
            else
                p1++;
        }
        return p1;
    }

[Leetcode] Reverse Words in a String

Given an input string, reverse the string word by word.
For example,
Given s = "the sky is blue",
return "blue is sky the".
One way is to use the split function to split the words into an array. And then combine the words. In order to split multi spaces, we need to use "\\s+" instead of simple " ".


    public String reverseWords(String s) {
        if(s == null)
            return null;
        s = s.trim();
        String[] words = s.split("\\s+");
        StringBuffer sb = new StringBuffer();
        for(int i = words.length - 1; i >= 0; i--) {
            sb.append(words[i]);
            if(i != 0)
                sb.append(" ");
        }
        String res = sb.toString();
        return res;
    }

Another way is to write it in place without split function. We could first trim the string to remove the leading and tailing spaces, this would ease the translation.

    public String reverseWords(String s) {
        s = s.trim();
        if(s.length() == 0)
            return s;
        int p1 = s.length() - 1, p2 = s.length() - 1;
        StringBuffer sb = new StringBuffer();
        while(p1 >= 0) {
            while(p1 >= 0 && s.charAt(p1) == ' ')
                p1--;
            p2 = p1;
            while(p1 >= 0 && s.charAt(p1) != ' ')
                p1--;
            sb.append(s.substring(p1+1, p2+1));
            if(p1 != p2)
                sb.append(" ");
        }
        String res = sb.toString();
        // remove the last space
        res = res.substring(0, res.length() - 1);
        return res;
    }

I prefer the first method since it is much cleaner, however the second one is often asked as a follow up.

2014年11月21日星期五

[Leetcode] Search for a Range

Given a sorted array of integers, find the starting and ending position of a given target value.
Your algorithm's runtime complexity must be in the order of O(log n).
If the target is not found in the array, return [-1, -1].
For example,
Given [5, 7, 7, 8, 8, 10] and target value 8,
return [3, 4].

The variation of traditional binary search. In order to be consisted with the version of binary search I'm most comfortable with, I used one kinds of the implementation that is most similar with the original one to find the first occurrence and the last occurrence . There are many other ways of implementing the functionality and you need only to recite one of them.


public class Solution {
    public int[] searchRange(int[] A, int target) {
        int[] res = new int[2];
        res[0] = left(A, target);
        res[1] = right(A, target);
        return res;
    }
    
    private int left(int[] A, int target) {
        int l = 0, r = A.length-1, result = -1;
        while(l <= r) {
            int mid = l + (r - l) / 2;
            if(A[mid] == target) {
                result = mid;
                r = mid - 1;
            }
            else if(A[mid] > target)
                r = mid - 1;
            else
                l = mid + 1;
        }
        return result;
    }
    
    private int right(int[] A, int target) {
        int l = 0, r = A.length-1, result = -1;
        while(l <= r) {
            int mid = l + (r - l) / 2;
            if(A[mid] == target) {
                result = mid;
                l = mid + 1;
            }
            else if(A[mid] > target)
                r = mid - 1;
            else
                l = mid + 1;
        }
        return result;
    }
}

2014年11月18日星期二

[Algorithm] One Edit Apart

Given two strings, return boolean True/False, if they are only one edit apart.Edit can be insert/delete/update of only one character in the string.

For example:
-True
xyz,xz
xyz, xyk
xy, xyz


-False
xyz, xyz
xyz,xzy 

x, xyz 

This problem is quite similar with edit distance. We could use the same code to calculate the minimum edit distance to change str1 to str2, and check if it is equal to one or not. However, we could use much simple code with O(n) time complexity. The core idea is that there is only one edit. So we could have several discussions (we assume str1 is the longer string):


  1. The difference of length is greater than 2, at least 2 edit distance, we could directly return false;
  2. The length are equal, there must be one and only one character differs, O(n) time to check;
  3. The length is differ by one, str1 must have one more character than str2. From the head of str2, check each character with str1, if at i we find there is a different character, we compare the str2(i, ...,end) with str1(i+1, ..., end) to see if there is only one character less and all others are the same;

import java.util.*;

public class OneEditApart {
 public static boolean match(String str1, String str2) {
  if(str1.length() < str2.length()) {
   String temp = str2;
   str2 = str1;
   str1 = temp;
  } // always assume str1 is longer than str2
  
  // length differ more than 2 would not match
  if(str1.length() - str2.length() >= 2)
   return false;
  // length equal then must have one and only one character differ
  else if(str1.length() == str2.length()) {
   for(int i = 0; i < str1.length(); i++) {
    if(str1.charAt(i) != str2.charAt(i)) 
     return str1.substring(i+1).equals(str2.substring(i+1));
   }
   return false;
  }
  // length is differ by one, str1 must have one character more than str2
  else {
   for(int i = 0; i < str2.length(); i++) {
    if(str1.charAt(i) != str2.charAt(i)) 
     return str1.substring(i+1).equals(str2.substring(i));
   }
   return true;
  }
 }
 
 public static void main(String[] args) {
  Scanner scan = new Scanner(System.in);
  while(scan.hasNext()) {
   String str1 = scan.next();
   String str2 = scan.next();
   System.out.println(match(str1, str2));
  }
 }
}

2014年11月17日星期一

[Data Structure] Segment Tree

Segment Tree is useful for range sum and update. Given an array A, we have two types of query, one is give the sum of elements in the range [l ,..., r] and the other is update the A[i] with a incremental or decrease. Using Segment Tree, both of the two operation can be done in O(logn) time.

Here is a more detail post about segment tree:http://www.geeksforgeeks.org/segment-tree-set-1-sum-of-given-range/


import java.util.*;

public class SegmentTree {
 public static class TreeNode {
  int val, l ,r;
  TreeNode left, right;
  public TreeNode(int val, int l, int r) {
   this.val = val;
   this.l = l;
   this.r = r;
  }
 }
 
 public static TreeNode buildTree(int[] A, int l, int r) {
  if(l == r) {
   TreeNode node = new TreeNode(A[l], l, r);
   return node;
  }
  else {
   int mid = l + (r - l) / 2;
   TreeNode left = buildTree(A, l, mid);
   TreeNode right = buildTree(A, mid+1, r);
   TreeNode node = new TreeNode(left.val + right.val, l, r);
   node.left = left;
   node.right = right;
   return node;
  }
 }
 
 public static int getSum(TreeNode node, int l, int r) {
  if(node.l >= l && node.r <= r) {
   return node.val;
  }
  else if(node.r < l || node.l > r) {
   return 0;
  }
  else {
   return getSum(node.left, l, r) + getSum(node.right, l, r);
  }
 }
 
 public static void update(TreeNode node, int val, int ind) {
  if(node == null)
   return;
  if(node.l > ind || node.r < ind) {
   return;
  }
  else {
   node.val += val;
   update(node.left, val, ind);
   update(node.right, val, ind);
  }
 }
 
 public static void main(String[] args) {
  Scanner scan = new Scanner(System.in);
  while(scan.hasNext()) {
   int n = scan.nextInt();
   int[] A = new int[n];
   for(int i = 0; i < n; i++)
    A[i] = scan.nextInt();
   TreeNode root = buildTree(A, 0, n-1);
   update(root, 2, 0);
   update(root, 100, 3);
   update(root, -9, 9);
   int l, r;
   while(scan.hasNext()) {
    l = scan.nextInt();
    r = scan.nextInt();
    System.out.println(getSum(root, l, r));
   }
  }
 }
}

2014年11月15日星期六

[Data Structure] Find the kth largest or kth smallest elements in a given array

Given an array, which is not ordered. You are asked to find all kth largest or kth smallest elements in it.

This question is quite popular. A very naive method is to sort the array first, then we find all kth largest or kth smallest elements. The time complexity is typically O(nlogn).
However, we could use a data structure called heap to improve the time complexity.

We first handle the kth largest case. In this case, we could use a small-end heap with capacity k. Then we sweep the array, for each element, if the heap is not full, we put it in, other wise we compare it with the top element of the heap, if it is larger than the top, we throw the current top away and put the element into heap. At the end, the heap will filled with kth largest elements, with the smallest one exist on the top.

Why this work? We consider the situation when the heap is full. The top would be the smallest one among all k elements. When a new element is less than or equal to the top, we know that it could not be selected, since there already exist k elements large or equal to it. What if a new element is larger than top? we know top could be eliminate, since we have a new candidate, by removing the top, we get a group of better k large elements. So we remove the top and put the new element in. The process continue until we have examine all elements in the array. The time complexity is O(nlogk), so if k << n, it will much faster than O(nlogn).

Similarly, for the kth smallest case, we use big-end heap with capacity k. 

The code is below, we use PriorityQueue in Java as the heap and pass a comparator to it. We assume the input would be valid.


 public static void FindKthSmall(int[] A, int k) {
  int n = A.length;
  Comparator<Integer> myComparator = new Comparator<Integer>() {
   public int compare(Integer a, Integer b) {
    return b - a;
   }
  };
  PriorityQueue<Integer> pq = new PriorityQueue<Integer>(k, myComparator);
  for(int i = 0; i < n; i++) {
   if(pq.size() == k) {
    if(A[i] < pq.peek()) {
     pq.remove();
     pq.add(A[i]);
    }
   }
   else {
    pq.add(A[i]);
   }
  }
  while(pq.size() != 0) {
   System.out.print(pq.peek() + " ");
   pq.remove();
  }
  System.out.println("");
 }


 public static void FindKthLarge(int[] A, int k) {
  int n = A.length;
  PriorityQueue<Integer> pq = new PriorityQueue<Integer>(k);
  for(int i = 0; i < n; i++) {
   if(pq.size() == k) {
    if(A[i] > pq.peek()) {
     pq.remove();
     pq.add(A[i]);
    }
   }
   else {
    pq.add(A[i]);
   }
  }
  while(pq.size() != 0) {
   System.out.print(pq.peek() + " ");
   pq.remove();
  }
  System.out.println("");
 }

2014年11月5日星期三

[Leetcode] Anagrams

Given an array of strings, return all groups of strings that are anagrams.
Note: All inputs will be in lower-case.
We sort each string in alphabet order, then each anagrams would have the same result. We could use this as the key to group all the anagrams in a hashmap. The time complexity of this method would be O(n*mlogm) where m is the average length of all strings. A better way is to use count sort of the strings since there are only 26 characters of them. The time complexity would reduce to O(n*m).

    public ArrayList<String> anagrams(String[] strs) {
        HashMap<String, List<String>> map = new HashMap<String, List<String>>();
        for(int i = 0; i < strs.length; i++) {
            char[] chs = strs[i].toCharArray();
            Arrays.sort(chs);
            String str = new String(chs);
            if(map.containsKey(str) == true) {
                map.get(str).add(strs[i]);
            }
            else {
                List<String> list = new ArrayList<String>();
                list.add(strs[i]);
                map.put(str, list);
            }
        }
        ArrayList<String> res = new ArrayList<String>();
        for(String key : map.keySet()) {
            if(map.get(key).size() > 1) {
                for(String str : map.get(key)) 
                    res.add(str);
            }
        }
        
        return res;
    }

[Leetcode] Sqrt

Implement int sqrt(int x).
Compute and return the square root of x.
Using the idea from Binary Search. Pay attention to some corner case.

    
public int sqrt(int x) {
        if(x < 2)
            return x;
        int i = 1, j = x / 2;
        while(i <= j) {
            int mid = i + (j - i) / 2;
            if(mid == x / mid) 
                return mid;
            else if(mid < x / mid)
                i = mid + 1;
            else 
                j = mid - 1;
        }
        return j;
    }

Another way is to use the Newton method.

    public int sqrt(int x) {
        if(x < 2)
            return x;
        double eps = 0.0000001;
        double oldValue = x, newValue = 1;
        while(Math.abs(oldValue - newValue) > eps) {
            oldValue = newValue;
            newValue = (newValue + x / newValue) / 2;
        }
        if((int)oldValue*(int)oldValue > x)
            oldValue--;
        return (int)oldValue;
    }

[Leetcode] Pow(x, n)

Implement pow(xn).
Using D and C. When we calculate n, we could use the result of n/2.

  1. If n is even, pow(x, n) = pow(x, n/2) * pow(x, n/2);
  2. If n is odd, pow(x, n) = pow(x, n/2) * pow(x, n/2) * x;
When n is negative, we inverse x and make n positive. Be careful if n is the MIN_VALUE, in this case you could not just simply make n positive since you would get a overflow if you still use integer.

    public double pow(double x, int n) {
        if(n == 0)
            return 1;
        if(n < 0) {
            x = 1 / x;
            if(n == Integer.MIN_VALUE)
                return x * pow(x, Integer.MAX_VALUE);
            else
                return pow(x, -n);
        }
        /*double res = 1;
        while(n != 0) {
            if(n % 2 == 1)
                res = res * x;
            x = x * x;
            n = n / 2;
        }
        return res;*/

        double res = pow(x, n/2);
        if(n % 2 == 0)
            return res*res;
        else
            return res*res*x;
    }

[Leetcode] Find Minimum in Rotated Sorted Array II

Follow up for "Find Minimum in Rotated Sorted Array":
What if duplicates are allowed?
Would this affect the run-time complexity? How and why?
Suppose a sorted array is rotated at some pivot unknown to you beforehand.
(i.e., 0 1 2 4 5 6 7 might become 4 5 6 7 0 1 2).
Find the minimum element.
The array may contain duplicates.

The code in this post is somewhat complicated, I have posted another solution on my gist which is available here:https://gist.github.com/pyemma/2dbe6f9bbb43f3881153


The key idea is to use the relationship of A[mid] with A[left] and A[right], here, left and right corresponding the portion of subarray we are trying to find the minimum. If there is no duplicate, we could first compare A[mid] with its left and right neighbor to see if we have find the answer, if no answer, we shrink the array we trying to find the minimum.

If the original array is in increasing order, then we directly return A[0]. However, if not, like the example, we could find that there are two monotony interval, from 4 to 7 and from 0 to 2. The element in the first one would all be larger than or equal to the one in the second one. We could easily get:

  1. If A[mid] > A[left], then we must located in the first interval, and what we need to do is to discard the portion of array before mid, since the minimum would not be there.
  2. If A[mid] < A[right], then we must located in the second interval, we could discard all the array behind the mid.
  3. If we could not make a judgement, since there are duplicates. So we move left and right until we could make a judge. Since these duplicates are of no use, discarding them would be okay.

public class Solution {
    public int findMin(int[] num) {
        int n = num.length;
        if(n == 1 || num[0] < num[n-1])
            return num[0];
        int l = 0, r = n-1;
        while(l < r) {
            int mid = l + (r - l) / 2;
            if(mid > 0 && num[mid] < num[mid-1])
                return num[mid];
            if(mid < n-1 && num[mid] > num[mid+1])
                return num[mid+1];
            if(num[mid] > num[l])
                l = mid + 1;
            else if(num[mid] < num[r])
                r = mid - 1;
            else {
                while(l < mid && num[mid] == num[l])
                    l++;
                while(r > mid && num[mid] == num[r])
                    r--;
            }
        }
        return num[l];
    }
}

[Leetcode] Valid Palindrome

Given a string, determine if it is a palindrome, considering only alphanumeric characters and ignoring cases.
For example,
"A man, a plan, a canal: Panama" is a palindrome.
"race a car" is not a palindrome.
Note:
Have you consider that the string might be empty? This is a good question to ask during an interview.
For the purpose of this problem, we define empty string as valid palindrome.
We each time compare the two ends' character, if they are not the same, it could not be a palindrome. During the process, we need to skip all non alphanumeric characters. Here, we need to pay attention to some corner case, such as all the character is non alphanumeric characters, if we do not check again before we actually compare the two characters, the wrong answer would be given.
    public boolean isPalindrome(String s) {
        if(s.length() == 0)
            return true;
        s = s.toLowerCase();
        int i = 0, j = s.length() - 1;
        while(i < j) {
            while(i < j && !((s.charAt(i) >= '0' && s.charAt(i) <= '9') || (s.charAt(i) >= 'a' && s.charAt(i) <= 'z')))
                i++;
            while(i < j && !((s.charAt(j) >= '0' && s.charAt(j) <= '9') || (s.charAt(j) >= 'a' && s.charAt(j) <= 'z')))
                j--;
            if(i < j && s.charAt(i) != s.charAt(j))
                return false;
            i++; j--;
        }
        return true;
    }

2014年11月2日星期日

[Leetcode] 4Sum

Given an array S of n integers, are there elements abc, and d in S such that a + b + c + d = target? Find all unique quadruplets in the array which gives the sum of target.
Note:
  • Elements in a quadruplet (a,b,c,d) must be in non-descending order. (ie, a ≤ b ≤ c ≤ d)
  • The solution set must not contain duplicate quadruplets.
    For example, given array S = {1 0 -1 0 -2 2}, and target = 0.

    A solution set is:
    (-1,  0, 0, 1)
    (-2, -1, 1, 2)
    (-2,  0, 0, 2)
The same idea with 3sum.

public class Solution {
    public List<List<Integer>> fourSum(int[] num, int target) {
        List<List<Integer>> res = new ArrayList<List<Integer>>();
        int n = num.length;
        if(n < 4)
            return res;
        Arrays.sort(num);
        int pre = num[0];
        for(int i = 0; i < n-3; i++) {
            if(i > 0 && pre == num[i])
                continue;
            pre = num[i];
            int npre = num[i+1];
            for(int j = i+1; j < n-2; j++) {
                if(j > i+1 && npre == num[j])
                    continue;
                npre = num[j];
                int left = j + 1;
                int right = n - 1;
                while(left < right) {
                    int sum = num[i] + num[j] + num[left] + num[right];
                    if(sum == target) {
                        ArrayList<Integer> list = new ArrayList<Integer>();
                        list.add(num[i]); list.add(num[j]);
                        list.add(num[left]); list.add(num[right]);
                        res.add(list);
                        left++;
                        while(left < right && num[left] == num[left-1])
                            left++;
                    }
                    else if(sum > target) {
                        right--;
                        while(left < right && num[right] == num[right+1])
                            right--;
                    }
                    else {
                        left++;
                        while(left < right && num[left] == num[left-1])
                            left++;
                    }
                }
            }
        }
        return res;
    }
}

[Leetcode] 3Sum

Given an array S of n integers, are there elements abc in S such that a + b + c = 0? Find all unique triplets in the array which gives the sum of zero.
Note:
  • Elements in a triplet (a,b,c) must be in non-descending order. (ie, a ≤ b ≤ c)
  • The solution set must not contain duplicate triplets.
    For example, given array S = {-1 0 1 2 -1 -4},

    A solution set is:
    (-1, 0, 1)
    (-1, -1, 2)
We first sort the array, then enumerate the first element of the three integers, then we look at the right part of the first element, that is the subarray with the element greater or equal with the element. We start from the left-most part and right-most part of this subarray, slowly narrow this "window" to try to find the solution.

  1. if num[i] + num[left] + num[right] == 0, we find a solution
  2. if num[i] + num[left] + num[right] < 0, we know that we could not move the right part, since it would make the sum even smaller, so we need to move left
  3. if num[i] + num[left] + num[right] > 0, we could not move left so we move right
In the process, when the new swept element is the same with the prior one, we should skip this element otherwise it would generate duplicate triplets.

All other K-sum problem could be solve in this idea, first sort the array, then enumerate all leading k - 2 elements, then find the remaining two elements using this narrowing window method. The final time complexity is O(N^(k-1)).

public class Solution {
    public ArrayList<ArrayList<Integer>> threeSum(int[] num) {
        ArrayList<ArrayList<Integer>> res = new ArrayList<ArrayList<Integer>>();
        int n = num.length;
        if(n < 3)
            return res;
        
        Arrays.sort(num);
        int pre = num[0];
        for(int i = 0; i < n-2; i++) {
            if(i > 0 && pre == num[i])
                continue;
            pre = num[i];
            int left = i + 1;
            int right = n - 1;
            while(left < right) {
                int sum = num[i] + num[left] + num[right];
                if(sum == 0) {
                    ArrayList<Integer> list = new ArrayList<Integer>();
                    list.add(num[i]);
                    list.add(num[left]);
                    list.add(num[right]);
                    res.add(list);
                    left++;
                    while(left < right && num[left] == num[left-1])
                        left++;
                }
                else if(sum > 0) {
                    right--;
                    while(left < right && num[right] == num[right+1])
                        right--;
                }
                else {
                    left++;
                    while(left < right && num[left] == num[left-1])
                        left++;
                }
            }
        }
        
        return res;
    }
}