Wednesday, March 18, 2015

Min Stack

Design a stack that supports push, pop, top, and retrieving the minimum element in constant time.
  • push(x) -- Push element x onto stack.
  • pop() -- Removes the element on top of the stack.
  • top() -- Get the top element.
  • getMin() -- Retrieve the minimum element in the stack.
Solution: one stack
class MinStack {
    int min;
    Stack stack;
    
    public MinStack() {
        stack = new Stack();
        min = Integer.MAX_VALUE;
    }
    
    public void push(int x) {
        if(x <= min) {
            stack.push(min);
            min = x;
        }
        stack.push(x);
    }

    public void pop() {
        if(stack.isEmpty())
            return;
        int temp = stack.pop();
        if(temp == min && !stack.isEmpty()) {
            min = stack.pop();
        }
    }

    public int top() {
        if(stack.isEmpty()) {
            return -1;
        }
        return stack.peek();
    }

    public int getMin() {
        return min;
    }
}

Find Nth Fibonacci Number

The Fibonacci numbers are the numbers in the following integer sequence.
0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 141, ……..
In mathematical terms, the sequence Fn of Fibonacci numbers is defined by the recurrence relation
  F_n = F_{n-1} + F_{n-2}
with seed values
   F_0 = 0 \quad\text{and}\quad F_1 = 1.
Write a function int fib(int n) that returns F_n. For example, if n = 0, then fib() should return 0. If n = 1, then it should return 1. For n > 1, it should return F_{n-1} + F_{n-2}
Solution1: dp
Avoid the repeated calculating. Time Complexity: O(n). Extra Space: O(n).
public class FindNthFibonacciNumber {
    public static void main(String[] args) {
        int n = 9;
        System.out.println(fib(n));
    }
 
    public static int fib(int n) {
        if(n == 0)
            return 0;
        if(n == 1)
            return 1;
  
        int[] dp = new int[n + 1];
        dp[0] = 0;
        dp[1] = 1;
        for(int i = 2; i <= n; i++) {
            dp[i] = dp[i - 1] + dp[i - 2];
        }
  
        return dp[n];
    }
  
}
Solution2Space Optimized 
Storing the previous two numbers only because that is all we need to get the next Fibonacci number in series.
Time Complexity: O(n). Extra Space: O(1).
//space optimized
 public static int fib(int n) {
     int a = 0;
     int b = 1;
  
     if(n == 0) {
        return a;
     }
  
     for(int i = 2; i <= n; i++) {
         int c = a + b;
         a = b;
         b = c;
     }
     return b;
 }

Reference: http://www.geeksforgeeks.org/program-for-nth-fibonacci-number/ 
Follow UpHow to check whether n is Fibonacci number
SolutionA number is Fibonacci if and only if one or both of (5*n2 + 4) or (5*n2 – 4) is a perfect square

//A number is Fibonacci if and only if one or both of (5*n2 + 4) or (5*n2 – 4) is a perfect square
 public static boolean checkFib(int n) {
     return isPerfectSquare(5*n*n + 4) || isPerfectSquare(5*n*n - 4);
 }
 
 public static boolean isPerfectSquare(int x) {
     int s = (int) Math.sqrt(x);
     if(s * s == x) {
         return true;
     }else {
         return false;
     }
 }

Compare Version Numbers

Compare two version numbers version1 and version2.
If version1 > version2 return 1, if version1 < version2 return -1, otherwise return 0.
You may assume that the version strings are non-empty and contain only digits and the . character.
The . character does not represent a decimal point and is used to separate number sequences.
For instance, 2.5 is not "two and a half" or "half way to version three", it is the fifth second-level revision of the second first-level revision.
Here is an example of version numbers ordering:
0.1 < 1.1 < 1.2 < 13.37
Solution
先根据点split strings,存在String[]里面。
从高位(第一个)开始对比,如果version1大,则返回1,如果version2大,则返回-1。
如果version1比较长,查看长出来的部分是否大于0, 是则返回1.
如果version2比较长,查看长出部分时候大于0, 是则返回-1。
其他情况返回0.
复杂度是O(n).
public class Solution {
    public int compareVersion(String version1, String version2) {
        String[] v1 = version1.split("\\.");
        String[] v2 = version2.split("\\.");
        
        for(int i = 0; i < v1.length || i < v2.length; i++) {
            if(i < v1.length && i < v2.length) {
                if(Integer.valueOf(v1[i]) > Integer.valueOf(v2[i])) {
                    return 1;
                }
                if(Integer.valueOf(v1[i]) < Integer.valueOf(v2[i])) {
                    return -1;
                }
            }else if(i < v1.length) {  //version1 is longer than version2
                if(Integer.valueOf(v1[i]) > 0) {
                    return 1;
                }  
            }else {  //version2 is longer than version1
                if(Integer.valueOf(v2[i]) > 0) {
                    return -1;
                }
            }
        }
        return 0;
    }
}

Lowest Common Ancestor of a Binary Search Tree

Given a binary search tree (BST), find the lowest common ancestor (LCA) of two given nodes in the BST.
According to the definition of LCA on Wikipedia: “The lowest common ancestor is defined between two nodes v and w as the lowest node in T that has both v and w as descendants (where we allow a node to be a descendant of itself).”
        _______6______
       /              \
    ___2__          ___8__
   /      \        /      \
   0      _4       7       9
         /  \
         3   5
For example, the lowest common ancestor (LCA) of nodes 2 and 8 is 6. Another example is LCA of nodes 2 and 4 is 2, since a node can be a descendant of itself according to the LCA definition.
Solution: bottom-up
Definition: The lowest common ancestor is defined between two nodes v and w as the lowest node in T that has both v and w as descendants (where we allow a node to be a descendant of itself).
We traverse from the bottom, and once we reach a node which matches one of the two nodes, we pass it up to its parent. 
The parent would then test its left and right subtree if each contain one of the two nodes. 
If yes, then the parent must be the LCA and we pass its parent up to the root. 
If not, we pass the lower node which contains either one of the two nodes (if the left or right subtree contains either A or B), or NULL (if both the left and right subtree does not contain either A or B) up.
Complexity is O(n).

/**
 * Definition of TreeNode:
 * public class TreeNode {
 *     public int val;
 *     public TreeNode left, right;
 *     public TreeNode(int val) {
 *         this.val = val;
 *         this.left = this.right = null;
 *     }
 * }
 */
public class Solution {
    /**
     * @param root: The root of the binary search tree.
     * @param A and B: two nodes in a Binary.
     * @return: Return the least common ancestor(LCA) of the two nodes.
     */
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode A, TreeNode B) {
        // write your code here
        if(root == null) {
            return null;
        }
        
        if(root == A || root == B) {
            return root;
        }
        
        TreeNode left = lowestCommonAncestor(root.left, A, B);
        TreeNode right = lowestCommonAncestor(root.right, A, B);
        
        if(left != null && right != null) {  // if A and B are on both sides
            return root;
        }
        
        if(left != null) {  // either one of A,B is on one side OR A,B is not in L&R subtrees
            return left;
        }else {
            return right;
        }
    }
}

Find kth largest/smallest number in array

Write an efficient program for printing k largest elements in an array. Elements in array can be in any order.
For example, if given array is [1, 23, 12, 9, 30, 2, 50] and you are asked for the largest 3 elements i.e., k = 3 then your program should print 50, 30 and 23.

Solution1: minHeap
此处找的是k个最大elements,也可以先把array sort一下,然后直接取k个。复杂度和minHeap一样。
Min heap是把最小的从queue里踢出,所以最后留下的是最大的。
In a Min Heap this property will be “If A is a parent node of B then key(A) is less than key(B) with the same ordering applying across the heap.” 
And in a max heap the key(A) will be greater than Key(B).
Time complexity is O(nlogn),heap在排序的时候复杂度是O(logn).
Java program to implement max heap
Java program to implement min heap

public class FindKMaximumInteger {
 public static void main(String[] args) {
  int[] arr = { 3, 46, 2, 56, 3, 38, 93, 45, 6, 787, 34, 76, 44, 6, 7, 86, 8, 44, 56 };
  int k = 5;
  int[] result = findKMaximum(arr, k);
  for (int i : result) {
     System.out.print(i + ",");
  }
 }
 
 public static int[] findKMaximum(int[] n, int k) {
  if(n == null || n.length == 0) {
   return null;
  }
  
  PriorityQueue minHeap = new PriorityQueue();
  for(int i = 0; i < n.length; i++) {
   int cur = n[i];
   if(minHeap.size() < k) {
    minHeap.add(cur);
   }else if(cur > minHeap.peek()){   // 如果find kth minimum integer, 此处换成cur < minHeap.peek()
    minHeap.poll();  //poll()踢出的是根元素
    minHeap.add(cur);
   }  
  }
  
  int[] res = new int[k];
  int index = 0;
  while(minHeap.size() != 0) {
   res[index] = minHeap.poll();
   index++;
  }
  
  return res;
 }
}
Solution2: quick select
此处找的是第k个最大element。quick select 还可以用于找中位数的题。
Like with quicksort, select a random element from the list, and place every item that is smaller to the first half of the array, and every element that is equal to or greater than the pivot, in the second half (the ‘half’ is not entirely correct, as it is possible that the result will not be exactly ‘half’).
如果是找第k个最大,则把大于等于pivot的放在左侧,小于pivot的放在右侧。
如果是找第k个最小,则相反。
时间复杂度是O(n).
//Quick select!
 public static int findKth(int[] n, int k) {
     if(n == null || n.length < k) {
        return 0;
     }
  
     int l = 0, r = n.length - 1;
     while(l < r) {
         int pivot = (l + r) / 2;
         int pivotValue = n[pivot];
         int store = l;
   
         n[pivot] = n[r];
         n[r] = pivotValue;
         for(int i = l; i < r; i++) {
         //for each number, if its greater than the pivot, move it to the left, otherwise leave it on the right
             if(n[i] > pivotValue) {  //if we want to find kth SMALLEST, change to n[i] < pivotValue
                 int temp = n[store];
                 n[store] = n[i];
                 n[i] = temp;
                 store++;
             }
         }
         n[r] = n[store];
         n[store] = pivotValue;  //move the pivot to its correct absolute location in the list
   
         //pick the correct half of the list you need to parse through to find your K, and ignore the other half
         if(store < k) {
             l = store + 1;
         }else {
             r = store;
         }
     }
     return n[k];
 }

Tuesday, March 10, 2015

Anagrams

Given an array of strings, return all groups of strings that are anagrams.
Note: All inputs will be in lower-case.
(An anagram is a type of word play, the result of rearranging the letters of a word or phrase to produce a new word or phrase, using all the original letters exactly once.)
Solution1: with hashmap and iterator
排序后的字符串可以作为一个key,也就是某一个class的id,如此只要对每一个字符串排序,然后建立一个hashmap,key是排序后的串,而value是所有属于这个key类的字符串,这样就可以比较简单的进行分类。假设我们有n个字符串,字符串最大长度是k,那么该算法的时间复杂度是O(nklogk),其中O(klogk)是对每一个字符串排序(如果用线性算法也可以提高)。空间复杂度则是O(nk),即hashmap的大小。
public class Solution {
    public ArrayList anagrams(String[] strs) {
        ArrayList res = new ArrayList();
        if(strs == null || strs.length == 0)
            return res;
        
        //用sort过的string作为key, anagrams的arraylist作为value
        HashMap> map = new HashMap>();
        for(int i = 0; i < strs.length; i++) {
            char[] arr = strs[i].toCharArray();
            Arrays.sort(arr);
            String str = new String(arr);
            
            if(map.containsKey(str)) {
                map.get(str).add(strs[i]);
            }else {
                ArrayList list = new ArrayList();
                list.add(strs[i]);
                map.put(str, list);
            }
        }
        
        Iterator iter = map.values().iterator();
        while(iter.hasNext()) {
            ArrayList item = (ArrayList)iter.next();
            if(item.size() > 1) {
                res.addAll(item);
            }
        }
        
        return res;
    }
}
Solution2: with hashmap and set
public class Solution {
    public ArrayList anagrams(String[] strs) {
        ArrayList res = new ArrayList();
        if(strs == null || strs.length == 0)
            return res;
        
        //用sort过的string作为key, anagrams的arraylist作为value
        HashMap> map = new HashMap>();
        for(int i = 0; i < strs.length; i++) {
            char[] arr = strs[i].toCharArray();
            Arrays.sort(arr);
            String str = new String(arr);
            
            if(map.containsKey(str)) {
                map.get(str).add(strs[i]);
            }else {
                ArrayList list = new ArrayList();
                list.add(strs[i]);
                map.put(str, list);
            }
        }
        
        Set set = map.keySet();
            
        for(String s : set) {
            ArrayList val = map.get(s);
            if(val.size() > 1) {
                res.addAll(val);
            }
        }
        return res;
    }
}

Regular Expression Matching

Implement regular expression matching with support for '.' and '*'.
'.' Matches any single character.
'*' Matches zero or more of the preceding element.

The matching should cover the entire input string (not partial).

The function prototype should be:
bool isMatch(const char *s, const char *p)

Some examples:
isMatch("aa","a") → false
isMatch("aa","aa") → true
isMatch("aaa","aa") → false
isMatch("aa", "a*") → true
isMatch("aa", ".*") → true
isMatch("ab", ".*") → true
isMatch("aab", "c*a*b") → true
Solution1: recursion
先看字符串s和p的从i和j开始的子串是否匹配,用递归的方法直到串的最后,最后回溯回来得到结果。假设现在走到s的i位置,p的j位置,情况分为下列两种: 
(1)p[j+1]不是'*'。只要判断当前s的i和p的j上的字符是否一样(如果有p在j上的字符是'.',也是相同),如果不同,返回false,否则,递归下一层i+1,j+1; 
(2)p[j+1]是'*'。此时看从s[i]开始的子串,假设s[i],s[i+1],...s[i+k]都等于p[j]那么意味着这些都有可能是合适的匹配,那么递归对于剩下的(i,j+2),(i+1,j+2),...,(i+k,j+2)都要尝试(j+2是因为跳过当前和下一个'*'字符)。 
public class Solution {
    public boolean isMatch(String s, String p) {

        return helper(s, p, 0, 0);
    }
    
     public boolean helper(String s, String p, int i, int j) {
         if(j == p.length())
             return i == s.length();

         if(j == p.length() - 1 || p.charAt(j+1) != '*') {
             if(i == s.length() || s.charAt(i) != p.charAt(j) && p.charAt(j) != '.')
                 return false;
             else
                 return helper(s, p, i+1, j+1);
         }
        
        //p.charAt(j+1)=='*'的情况
         while(i < s.length() && (p.charAt(j) == '.' || p.charAt(j) == s.charAt(i))) {
             if(helper(s, p, i, j+2))  //j+2是因为跳过当前和下一个'*'字符
                 return true;
             i++;
         }
         return helper(s, p, i, j+2);
     }
}
Solution2: DP
维护一个布尔数组res[i][j],代表s的前i个字符和p的前j个字符是否匹配(res的维度是s.length()+1,p.length()+1)。递推公式跟上面类似,分三种种情况: 
(1)p[j+1]不是'*'。情况比较简单,只要判断如果当前s的i和p的j上的字符一样(如果有p在j上的字符是'.',也是相同),并且res[i][j]==true,则res[i+1][j+1]也为true,res[i+1][j+1]=false; 
(2)p[j+1]是'*',但是p[j]!='.'。那么只要以下条件有一个满足即可对res[i+1][j+1]赋值为true: 
    1)res[i+1][j]为真('*'只取前面字符一次); 
    2)res[i+1][j-1]为真('*'前面字符一次都不取,也就是忽略这两个字符); 
    3)res[i][j+1] && s[i]==s[i-1] && s[i-1]==p[j-1](这种情况是相当于i从0到s.length()扫过来,如果p[j+1]对应的字符是‘*’那就意味着接下来的串就可以依次匹配下来,如果下面的字符一直重复,并且就是‘*’前面的那个字符)。 
(3)p[j+1]是'*',并且p[j]=='.'。因为".*"可以匹配任意字符串,所以在前面的res[i+1][j-1]或者res[i+1][j]中只要有i+1是true,那么剩下的res[i+1][j+1],res[i+2][j+1],...,res[s.length()][j+1]就都是true了。
时间复杂度是O(n^2),空间复杂度也是O(n^2)
Reference: http://blog.csdn.net/linhuanmars/article/details/21145563
public class Solution {
    public boolean isMatch(String s, String p) {
        if(s.length()==0 && p.length()==0)  
            return true;  
        if(p.length()==0)  
            return false;  
            
        boolean[][] res = new boolean[s.length()+1][p.length()+1];  
        res[0][0] = true;  
        for(int j=0;j
0 && res[0][j-1]) res[0][j+1]=true; if(j<1 data-blogger-escaped-continue="" data-blogger-escaped-for="" data-blogger-escaped-i="" data-blogger-escaped-if="" data-blogger-escaped-int="" data-blogger-escaped-j-1="" data-blogger-escaped-j="" data-blogger-escaped-p.charat="" data-blogger-escaped-res="">0&&res[i+1][j-1] || i>0 && j>0 && res[i][j+1]&&s.charAt(i)==s.charAt(i-1)&&s.charAt(i-1)==p.charAt(j-1)) res[i+1][j+1] = true; } } else { int i=0; while(j>0 && i