AdSense

Tuesday, June 28, 2016

Range Sum Query 2D - Immutable

Given a 2D matrix matrix, find the sum of the elements inside the rectangle defined by its upper left corner (row1, col1) and lower right corner (row2, col2).
Range Sum Query 2D
The above rectangle (with the red border) is defined by (row1, col1) = (2, 1) and (row2, col2) = (4, 3), which contains sum = 8.
Example:
Given matrix = [
  [3, 0, 1, 4, 2],
  [5, 6, 3, 2, 1],
  [1, 2, 0, 1, 5],
  [4, 1, 0, 1, 7],
  [1, 0, 3, 0, 5]
]

sumRegion(2, 1, 4, 3) -> 8
sumRegion(1, 1, 2, 2) -> 11
sumRegion(1, 2, 2, 4) -> 12
Note:
  1. You may assume that the matrix does not change.
  2. There are many calls to sumRegion function.
  3. You may assume that row1 ≤ row2 and col1 ≤ col2.

This question is not as easy as it looks like: the time limit will exceed if you just sum up everything when calling the function. A smarter way is to initialize a helper matrix in that each element (x, y) is the sum of matrix from (0, 0) to (x, y). Then whenever we need to call the function, we subtract from the helper matrix to get the answer.


public class NumMatrix {
    private int[][] sumMatrix;
    public NumMatrix(int[][] matrix) {
        if (matrix == null || matrix.length == 0 || matrix[0].length == 0) {
            sumMatrix = null;
        } else {
            sumMatrix = new int[matrix.length][matrix[0].length];
            for (int i = 0; i < matrix.length; i++) {
                sumMatrix[i][0] = matrix[i][0];
            }
            for (int i = 0; i < matrix.length; i++) {
                for (int j = 1; j < matrix[0].length; j++) {
                sumMatrix[i][j] = sumMatrix[i][j - 1] + matrix[i][j];
                }
            }
        
            for (int i = 1; i < matrix.length; i++) {
                for (int j = 0; j < matrix[0].length; j++) {
                    sumMatrix[i][j] += sumMatrix[i - 1][j]; 
                }
            }
        }
        
    }

    public int sumRegion(int row1, int col1, int row2, int col2) {
        if (sumMatrix == null)
            return 0;
        if (row1 == 0 && col1 == 0) {
            return sumMatrix[row2][col2];
        } else if (row1 == 0) {
            return sumMatrix[row2][col2] - sumMatrix[row2][col1 - 1];
        } else if (col1 == 0) {
            return sumMatrix[row2][col2] - sumMatrix[row1 - 1][col2];
        } else {
            return sumMatrix[row2][col2] - sumMatrix[row1 - 1][col2] - sumMatrix[row2][col1 - 1] 
            + sumMatrix[row1 - 1][col1 - 1];
        }
    }
}


Monday, June 27, 2016

Coin Change

You are given coins of different denominations and a total amount of money amount. Write a function to compute the fewest number of coins that you need to make up that amount. If that amount of money cannot be made up by any combination of the coins, return -1.
Example 1:
coins = [1, 2, 5], amount = 11
return 3 (11 = 5 + 5 + 1)
Example 2:
coins = [2], amount = 3
return -1.
Note:
You may assume that you have an infinite number of each kind of coin.

This is a dp problem. For each amount, find the possible combinations from the coins, return if the amount can be formed.


public int coinChange(int[] coins, int amount) {
        if (coins == null || coins.length == 0)
            return -1;
        int[] combinations = new int[amount + 1];
        Arrays.fill(combinations, 1, amount + 1, Integer.MAX_VALUE);
        
        for (int i = 0; i <= amount; i++) {
            for (int j = 0; j < coins.length; j++) {
                if (i + coins[j] <= amount && combinations[i] != Integer.MAX_VALUE) {
                    combinations[i + coins[j]] = Math.min(combinations[i] + 1, combinations[i + coins[j]]);
                }
            }
        }
        return combinations[amount] != Integer.MAX_VALUE ? combinations[amount] : -1;
    }


Additive Number

Additive number is a string whose digits can form additive sequence.
A valid additive sequence should contain at least three numbers. Except for the first two numbers, each subsequent number in the sequence must be the sum of the preceding two.
For example:
"112358" is an additive number because the digits can form an additive sequence: 1, 1, 2, 3, 5, 8.
1 + 1 = 2, 1 + 2 = 3, 2 + 3 = 5, 3 + 5 = 8
"199100199" is also an additive number, the additive sequence is: 1, 99, 100, 199.
1 + 99 = 100, 99 + 100 = 199
Note: Numbers in the additive sequence cannot have leading zeros, so sequence 1, 2, 03 or 1, 02, 3 is invalid.
Given a string containing only digits '0'-'9', write a function to determine if it's an additive number.
Follow up:
How would you handle overflow for very large input integers?
Iterative each combination of first and second number, then recursively check if the whole sequence is valid.

 public boolean isAdditiveNumber(String num) {
        if (num == null || num.length() < 3)
            return false;
        int len = num.length();
        for (int f_pos = 1; f_pos < len; f_pos++) {
            for (int s_pos = f_pos + 1; s_pos < len; s_pos++) {
                if (isValid(num, 0, f_pos, s_pos))
                    return true;
            }
        }
        return false;
    }
    
    private boolean isValid(String num, int start, int f_pos, int s_pos) {
        int len = num.length();
        if ((f_pos - start > 1 && num.charAt(start) == '0') || (s_pos - f_pos > 1 && num.charAt(f_pos) == '0'))
            return false;
        long first = Long.parseLong(num.substring(start, f_pos));
        long second = Long.parseLong(num.substring(f_pos, s_pos));
        String sum = String.valueOf(first + second);
        int next_pos = s_pos + sum.length();
        
        if(next_pos > len || !num.substring(s_pos, next_pos).equals(sum))
            return false;
        return next_pos == len ? true : isValid(num, f_pos, s_pos, next_pos);
        
    }


Sunday, June 26, 2016

Course schedule I and II

There are a total of n courses you have to take, labeled from 0 to n - 1. Some courses may have prerequisites, for example to take course 0 you have to first take course 1, which is expressed as a pair: [0,1] Given the total number of courses and a list of prerequisite pairs, is it possible for you to finish all courses? For example: 2, [[1,0]] There are a total of 2 courses to take. To take course 1 you should have finished course 0. So it is possible. 2, [[1,0],[0,1]] There are a total of 2 courses to take. To take course 1 you should have finished course 0, and to take course 0 you should also have finished course 1. So it is impossible.

The first problem requires us to find if there is a cycle in the graph, if there is, then its a false. It does not require topological sort, yet if you use traditional DFS, it will exceed time limit. However, we can do a little bit optimization to avoid traverse already traversed path. Instead of using a boolean to track visited nodes, we can use an int array. For visited node, we mark it as 1, for the node that is visited and the path that is rooted by it does not contain cycle, we mark it as 2. So along any path if we find a node that is marked as 2, we can save our time and return "true" directly.


 public boolean canFinish(int numCourses, int[][] prerequisites) {
        if (numCourses == 0 || prerequisites == null || prerequisites.length == 0)
            return true;
        Map<Integer, List<Integer>> map = new HashMap<>();
        for (int[] prequisit : prerequisites) {
            int klass = prequisit[0];
            if (!map.containsKey(prequisit[0]))
                map.put(klass, new ArrayList<>());
            map.get(klass).add(prequisit[1]);
        }
        int[] visited = new int[numCourses];
        for (int i = 0; i < numCourses; i++) {
            if (!helper(visited, map, i))
                return false;
        }
        return true;
    }
    
    private boolean helper(int[] visited, Map <Integer, List<Integer>> map, int i) {
        visited[i] = 1;
        //no prerequisit
        if (!map.containsKey(i)) {
            visited[i] = 2;
            return true;
        }
        for (int pre : map.get(i)) {
            if (visited[pre] == 2)
                break;
            if (visited[pre] == 1 || !helper(visited, map, pre))
                return false;
        }
        visited[i] = 2;
        return true;
    } 


The second problem, on the other hand, requires topological sort. Common approach to it is to first find all vertices with indegree 0. Then for each vertex with indegree 0, remove all its neighbor nodes. Iteratively perform this process until all nodes are found.

 public int[] findOrder(int numCourses, int[][] prerequisites) {
        List<Set<Integer>> adjList = new ArrayList<>();
        for (int i = 0; i < numCourses; i++) {
            adjList.add(new HashSet<>());
        }
        for (int i = 0; i < prerequisites.length; i++) {
            adjList.get(prerequisites[i][1]).add(prerequisites[i][0]);
        }
        int[] indegrees = new int[numCourses];
        for (Set<Integer> pre : adjList) {
            for (int i : pre)
                indegrees[i]++;
        }
        Queue<Integer> first = new LinkedList<>();
        for (int i = 0; i < numCourses; i++) {
            if (indegrees[i] == 0)
                first.add(i);
        }
        int[] rst = new int[numCourses];
        int count = 0;
        while (!first.isEmpty()) {
            int curr = first.poll();
            for (int i : adjList.get(curr)) {
                indegrees[i]--;
                if (indegrees[i] == 0)
                    first.add(i);
            }
            rst[count++] = curr;
        }
        return count == numCourses ? rst : new int[]{};
    }


I was considering using DFS for the problem. However, traditional DFS for topological sort requires DAG, which cannot be guaranteed by this problem.

Tuesday, June 14, 2016

Best Time to Buy and Sell Stock with Cooldown

Say you have an array for which the ith element is the price of a given stock on day i.
Design an algorithm to find the maximum profit. You may complete as many transactions as you like (ie, buy one and sell one share of the stock multiple times) with the following restrictions:
  • You may not engage in multiple transactions at the same time (ie, you must sell the stock before you buy again).
  • After you sell your stock, you cannot buy stock on next day. (ie, cooldown 1 day)
Example:
prices = [1, 2, 3, 0, 2]
maxProfit = 3
transactions = [buy, sell, cooldown, buy, sell]


Interestingly, I was looking at a solution online but it turned out it's too hard to understand, so I figured out my own solution, which is also accepted.

The approach is of course DP (just like other 4 problems). We need two helper array, one is for buy, the other is for sell. Each element in the two array represents the maximum profit got making the transaction.

In each day, either we buy the stock or not. The maximum profit will be the profit we got by selling stock two days ago (cool down for one day) and  the profit we got from yesterday (mot buy).

buyMaxProfit[i] = Math.max(sellMaxProfit[i - 2] - prices[i], buyMaxProfit[i - 1]);

In the sell part, we either sell the stock today or not. The maximum profit would be the profit we buy yesterday plus the price of selling the stock today (sell) or the profit we had yesterday (not sell).

sellMaxProfit[i] = Math.max(buyMaxProfit[i] + prices[i], sellMaxProfit[i - 1]);


    public int maxProfit(int[] prices) {
        int len = prices.length;
        if (len < 2) {
            return 0;
        }
        int[] buyMax = new int[len];
        buyMax[0] = -prices[0];
        buyMax[1] = Math.max(-prices[0], -prices[1]);
        int[] sellMax = new int[len];
        sellMax[0] = 0;
        sellMax[1] = Math.max(0, prices[1] - prices[0]);
        
        for (int i = 2; i < len; i++) {
            sellMax[i] = Math.max(buyMax[i - 1] + prices[i], sellMax[i - 1]);
            buyMax[i] = Math.max(sellMax[i - 2] - prices[i], buyMax[i - 1]);
        }
        return sellMax[len - 1];
    }


Monday, June 13, 2016

Bulb Switcher

There are n bulbs that are initially off. You first turn on all the bulbs. Then, you turn off every second bulb. On the third round, you toggle every third bulb (turning on if it's off or turning off if it's on). For the ith round, you toggle every i bulb. For the nth round, you only toggle the last bulb. Find how many bulbs are on after n rounds.
Example:
Given n = 3. 

At first, the three bulbs are [off, off, off].
After first round, the three bulbs are [on, on, on].
After second round, the three bulbs are [on, off, on].
After third round, the three bulbs are [on, off, off]. 

So you should return 1, because there is only one bulb is on.

Update 2016-10-11

This problem is more like a math problem. For bulb i, if its number of factors is odd, it will be turned on in the end, if its number of factors is even, it will be turned off in the end. However, only the square root of n has odd factors because all other factors exists in pair. For example, n = 36, its factors are (1, 36), (2, 18),  (3, 12), (4, 9), (6, 6), (9, 4), (12, 3), (18, 2), (1, 36).



I don't really like mathematical problems, part of the reason is that I'm not good at it. This problem is a typical math problem. And the code is:

public int bulbSwitch(int n) {
        if (n < 0)
            return 0;
        return (int)Math.sqrt(n);
        
    }


So easy, right? So why this is the case.

For every prime number, it only contains factor of 1 and itself, which means it will ultimately be turned off (turn on at 1st round and turn off at the-number-itself round).
For every square number, in the end it will be turned on because all other factors will be in pairs except its square root. Consider 4:
1 * 4, 2 * 2, 4 * 1
At first round, it will be the forth to turn on, off -> on
At second round, it will be the second to turn off, on -> off
At round four, it will be the first to turn on, off -> on

Consider 9:
1 * 9, 3 * 3, 9 * 1

For all other numbers, it will be turned off ultimately because all the factors are in pairs.

So the number of turned on lights depends on how many square number n has, which is its square root.

Count Numbers with Unique Digits


Given a non-negative integer n, count all numbers with unique digits, x, where 0 ≤ x < 10n.
Example:
Given n = 2, return 91. (The answer should be the total numbers in the range of 0 ≤ x < 100, excluding [11,22,33,44,55,66,77,88,99])

The trick of this problem is to find the pattern of how to find numbers with unique numbers. The code looks rather easy, but very confusing.

i = 1, 10: nothing is dupliated
i = 2, 9 * 9: the first digit has 9 options (exclude 0), the second digit also has 9 options (exclude the number already taken by the first digit, but include 0).
i = 3, 9 * 9 * 8: first two digits follows rules in i = 2, then the third digit has options that exclude all numbers taken by the previous two digits.
.
.
.
i     , 9 * 9 * 8 *... * (10 - i + 1),  the last digit has options that exclude those already chosen by all previous digits.

The final result is the sum of all results.

public int countNumbersWithUniqueDigits(int n) {
        if (n == 0)
            return 1;
        int rst = 10, count = 9;
        for (int i = 2; i <= n; i++) {
            count *= (10 - i + 1);
            rst += count;
        }
        return rst;
    }


Monday, June 6, 2016

Reconstruct Itinerary

I didn't think of using DFS approach at first and use a map instead. So I stuck when it reaches the end of the itinerary but the map is yet empty. Then I searched online for a while and realize it is a DFS problem, all I need to add with my first approach is to use a Stack. Later I use recursion again, and the first one is actually neater.

Iteration:

public List<string> findItinerary(String[][] tickets) {
        List<string> rst = new ArrayList<>();
        if (tickets == null || tickets.length == 0)
            return rst;
        Map<string, priorityqueue<string>> map = new HashMap<>();
        for (String[] ticket : tickets) {
            String from = ticket[0];
            if (!map.containsKey(from)) {
                map.put(from, new PriorityQueue<>());
            }
            map.get(from).add(ticket[1]);
        }
        Stack<string> temp = new Stack();
        temp.add("JFK");
        while (!temp.isEmpty()) {
            String from = temp.peek();
            if (map.containsKey(from) && map.get(from).size() > 0)
                temp.push(map.get(from).poll());
            else
                rst.add(temp.pop());
            }
        Collections.reverse(rst);
        return rst;
    }


Recursion:
public List findItinerary(String[][] tickets) {
        List<string> itinerary = new ArrayList<>();
        if (tickets == null || tickets.length == 0)
            return itinerary;
        Map<string, priorityqueue<string>> destinations = new HashMap<>();
        for (String[] ticket : tickets) {
            if (!destinations.containsKey(ticket[0]))
                destinations.put(ticket[0], new PriorityQueue<>());
            destinations.get(ticket[0]).offer(ticket[1]);
        }
        findItinerary("JFK", destinations, itinerary);
        Collections.reverse(itinerary);
        return itinerary;
        
    }
    private void findItinerary(String from, Map<string, priorityqueue<string>> destinations, List<string> itinerary) {
        if (!destinations.containsKey(from) || destinations.get(from).size() == 0) {
            itinerary.add(from);
            return;
        }
        PriorityQueue<string> curr = destinations.get(from);
        while (!curr.isEmpty()) {
            String to = curr.poll();
            findItinerary(to, destinations, itinerary);
        }
        itinerary.add(from);
    }

Sunday, June 5, 2016

Increasing Triplet Subsequence

Given an unsorted array return whether an increasing subsequence of length 3 exists or not in the array.
Formally the function should:
Return true if there exists i, j, k 
such that arr[i] < arr[j] < arr[k] given 0 ≤ i < j < k ≤ n-1 else return false.
Your algorithm should run in O(n) time complexity and O(1) space complexity.
Examples:
Given [1, 2, 3, 4, 5],
return true.
Given [5, 4, 3, 2, 1],
return false.

Initialize x1 and x2 to max value. Traverse the array, if num is less than x1, set x1 to num. Else if x1 < num < x2, set x2 to num. Else if num > x2, return true. The idea is to keep a sequence of triplet, and reduce the differences among the three numbers until find a solution.




public boolean increasingTriplet(int[] nums) {
        if (nums == null || nums.length < 3)
            return false;
        int x1 = Integer.MAX_VALUE, x2 = Integer.MAX_VALUE;
        for(int num : nums) {
            if (num < x1)
                x1 = num;
            else if (x1 < num && num < x2)
                x2 = num;
            else if (num > x2)
                return true;
        }
        return false;
    }


The second solution is also an accepted one, but it's too complicated and requires extra space.

public boolean increasingTriplet(int[] nums) {
        if (nums == null || nums.length < 3)
            return false;
        TreeMap<Integer, List<Integer>> map = new TreeMap<>();
        map.put(nums[0], new ArrayList<>());
        for (int i = 1; i < nums.length; i++){
            int num = nums[i];
            if (map.floorKey(num) != null) {
                for (Integer key : map.headMap(num).keySet()){
                    if (key == num)
                        continue;
                    List<Integer> values = map.get(key);
                    if (values.size() > 0 && num <= values.get(0))
                        values.clear();
                    values.add(num);
                    if (values.size() == 2)
                        return true;
                }

            }
            if (!map.containsKey(num))
                map.put(num, new ArrayList<>());
        }
        return false;
    }

Saturday, June 4, 2016

Self Crossing

You are given an array x of n positive numbers. You start at point (0,0) and moves x[0] metres to the north, then x[1] metres to the west, x[2] metres to the south,x[3] metres to the east and so on. In other words, after each move your direction changes counter-clockwise.
Write a one-pass algorithm with O(1) extra space to determine, if your path crosses itself, or not.
Example 1:
Given x = [2, 1, 1, 2],
┌───┐
│   │
└───┼──>
    │

Return true (self crossing)
Example 2:
Given x = [1, 2, 3, 4],
┌──────┐
│      │
│
│
└────────────>

Return false (not self crossing)
Example 3:


Given x = [1, 1, 1, 1],
┌───┐
│   │
└───┼>

Return true (self crossing)

I think this problem is quite "hard" to me. There are only three situations when the path will not cross itself:

  1. The number keeps increasing (which will form an growing spiral).
  2. The number keeps decreasing (which will form an shrinking spiral).
  3. The number increases first, then decreases, and never increases again.   

The harder part is to implement all three situations. Since our program should be one pass, we should check if the number keeps increasing (or decreasing), or if it changes its trend.

public boolean isSelfCrossing(int[] x) {
        if (x == null || x.length < 4)
            return false;
        int length = x.length;
        int t1 = 0, t2 = x[0], t3 = x[1], t4 = x[2], t5;
        boolean isIncrease = (t4 > t2);
        for (int i = 3; i < length; i++) {
            t5 = x[i];
            if (isIncrease && (t3 >= t5)) {
                //condition 1
                if ((t1 + t5) < t3 || ((i < length - 1) && x[i + 1] + t2 < t4))
                    isIncrease = false;
                //condition 2
                else if (i < length - 1)
                    return true;
            // condition 3
            } else if (!isIncrease && (t3 <= t5))
                return true;
            t1 = t2;
            t2 = t3;
            t3 = t4;
            t4 = t5;
        }
        return false;
    }






Palindrome Pairs

Given a list of unique words. Find all pairs of distinct indices (i, j) in the given list, so that the concatenation of the two words, i.e. words[i] + words[j] is a palindrome.
Example 1:
Given words = ["bat", "tab", "cat"]
Return [[0, 1], [1, 0]]
The palindromes are ["battab", "tabbat"]
Example 2:
Given words = ["abcd", "dcba", "lls", "s", "sssll"]
Return [[0, 1], [1, 0], [3, 2], [2, 4]]
The palindromes are ["dcbaabcd", "abcddcba", "slls", "llssssll"]

This one doesn't look like a hard one: the easiest way is to go through the whole array and find the solution. Yet it definitely will exceed time limit. A smarter way is first to use a map and store all the words and their positions. Then go through the list and find the following pattern:

1. If the word is palindrome, find if there is empty string exists.
2. Find if the reverse word exists in the list. 
3. For each word, traverse through the word and separate them to two parts: if one of the two parts is palindrome, find if there exists the reverse word of the other part. 
4. Make sure the position of the words are different. 


public class Solution {
    public List<List<Integer>> palindromePairs(String[] words) {
        List<List<Integer>> rst = new ArrayList<>();
        if (words == null || words.length == 0)
            return rst;
        Map<String, Integer> positions = new HashMap<>();
        for (int i = 0; i < words.length; i++) {
            positions.put(words[i], i);
        }
        for (int i = 0; i < words.length; i++) {
            String s = words[i];
            String rs = reverse(s);
            if (isPalindrome(s, "") && positions.containsKey("")) {
                int pos = positions.get("");
                if (pos != i) {
                    addToList(rst, i, pos);
                    addToList(rst, pos, i);
                }
                
            }
                
            if (positions.containsKey(rs) && positions.get(rs) != i) {
                int pos = positions.get(rs);
                addToList(rst, i, pos);
            }
                
            for (int j = 1; j < s.length(); j++) {
                String left = s.substring(0, j);
                String right = s.substring(j, s.length());
                String r_left = reverse(left);
                String r_right = reverse(right);
                if (isPalindrome(left, "") && positions.containsKey(r_right))
                    addToList(rst, positions.get(r_right),i);
                if (isPalindrome(right, "") && positions.containsKey(r_left))
                    addToList(rst, i, positions.get(r_left));
                    
            }
        }
        return rst;
    }
    
    private void addToList(List<List<Integer>> rst, int first, int second) {
        List<Integer> curr = new ArrayList<Integer>();
        curr.add(first);
        curr.add(second);
        rst.add(curr);
    }
    
    private boolean isPalindrome(String a, String b) {
        String ab = a + b;
        int start = 0;
        int end = ab.length() - 1;
        while (start < end) {
            if (ab.charAt(start) != ab.charAt(end))
                return false;
            start++;
            end--;
        }
        return true;
    }
    
    private String reverse(String s) {
        return new StringBuilder(s).reverse().toString();
    }
}

Friday, June 3, 2016

House Robber I, II and III


You are a professional robber planning to rob houses along a street. Each house has a certain amount of money stashed, the only constraint stopping you from robbing each of them is that adjacent houses have security system connected and it will automatically contact the police if two adjacent houses were broken into on the same night.
Given a list of non-negative integers representing the amount of money of each house, determine the maximum amount of money you can rob tonight without alerting the police.

The first one is just a simple DP problem.
public int rob(int[] nums) {
        if (nums == null || nums.length == 0)
            return 0;
        int len = nums.length;
        if (len == 1)
            return nums[0];
        int[] sum = new int[len];
        sum[0] = nums[0];
        sum[1] = Math.max(nums[0], nums[1]);
        for (int i = 2; i < len; i++) {
            sum[i] = Math.max(sum[i - 1], sum[i - 2] + nums[i]);
        }
        return sum[len - 1];
    }


Note: This is an extension of House Robber.
After robbing those houses on that street, the thief has found himself a new place for his thievery so that he will not get too much attention. This time, all houses at this place are arranged in a circle. That means the first house is the neighbor of the last one. Meanwhile, the security system for these houses remain the same as for those in the previous street.
Given a list of non-negative integers representing the amount of money of each house, determine the maximum amount of money you can rob tonight without alerting the police.

The second one, now the first house is connected with the last house, which means one of the house cannot be robbed. Then we can find the max money we can get if we rob nums[0] to nums[len - 2] and that we can get if nums[1] to nums[len - 1] are robbed.
public int rob(int[] nums) {
        if (nums == null || nums.length == 0)
            return 0;
        int len = nums.length;
        if (len == 1)
            return nums[0];
        int[] sum = new int[len];
        sum[0] = nums[0];
        sum[1] = Math.max(nums[0], nums[1]);
        return Math.max(max(nums, 0, len - 2), max(nums, 1, len - 1));
     }
     private int max(int[] nums, int start, int end) {
         if (start == end)
            return nums[start];
         int len = end - start + 1;
         int[] sum = new int[len];
         sum[0] = nums[start];
         sum[1] = Math.max(nums[start], nums[start + 1]);
         for (int i = 2; i < len; i++) {
             sum[i] = Math.max(sum[i - 1], sum[i - 2] + nums[start + i]);
         }
         return sum[len - 1];
     }


The thief has found himself a new place for his thievery again. There is only one entrance to this area, called the "root." Besides the root, each house has one and only one parent house. After a tour, the smart thief realized that "all houses in this place forms a binary tree". It will automatically contact the police if two directly-linked houses were broken into on the same night.
Determine the maximum amount of money the thief can rob tonight without alerting the police.
Example 1:
     3
    / \
   2   3
    \   \ 
     3   1
Maximum amount of money the thief can rob = 3 + 3 + 1 = 7.
Example 2:
     3
    / \
   4   5
  / \   \ 
 1   3   1
Maximum amount of money the thief can rob = 4 + 5 = 9.

The third one is a tree like structure. Consider a tree of two level, either the two leaves are robbed, or the root is robbed. Then we can recursively find the max money of robbing two leaves or root + leaves children.

public int rob(TreeNode root) { 
        return robHelper(root)[0];
        
    }
    
    private int[] robHelper(TreeNode root) {
        int[]sum = {0, 0};
        if (root == null) {
            return sum;
        }
        int[]sum_left = robHelper(root.left);
        int[]sum_right = robHelper(root.right);
        sum[1] = sum_left[0] + sum_right[0];
        sum[0] = Math.max(sum[1], sum_left[1] + sum_right[1] + root.val);
        return sum;
    }

Thursday, June 2, 2016

Counting Bits

Given a non negative integer number num. For every numbers i in the range 0 ≤ i ≤ num calculate the number of 1's in their binary representation and return them as an array.
Example:
For num = 5 you should return [0,1,1,2,1,2].
Follow up:
  • It is very easy to come up with a solution with run time O(n*sizeof(integer)). But can you do it in linear time O(n) /possibly in a single pass?
  • Space complexity should be O(n).
  • Can you do it like a boss? Do it without using any builtin function like __builtin_popcount in c++ or in any other language.


This is a DP problem. The first two numbers, 0 and 1, have 0 and 1 bits. From then on, each time we hit a number that is a power of 2, we have one more carries, but all other digits are repeated again from the very beginning.

    0        1
    0        1
                     10     11
                       1       2
100    101   110   111
    1        2       2       3


public int[] countBits(int num) {
        int[] bits = new int[num + 1];
        if (num < 0)
            return bits;
        bits[0] = 0;
        if (num == 0)
            return bits;
        bits[1] = 1;
        int index = 0;
        for (int i = 2; i <= num; i++) {
            if (isPowerOfTwo(i))
                index = 0;
            bits[i] = 1 + bits[index++];
        }
        return bits;
    }
    
    private boolean isPowerOfTwo(int num) {
        return (num & (num - 1)) == 0;
    }