Tuesday, February 14, 2017

Leetcode/各大家--146. LRU Cache(HashMap + Doubly LinkedList)

146. LRU Cache(HashMap + Doubly LinkedList)
hard
https://leetcode.com/problems/lru-cache/
Design and implement a data structure for Least Recently Used (LRU) cache. It should support the following operations: get and put.
get(key) - Get the value (will always be positive) of the key if the key exists in the cache, otherwise return -1.
put(key, value) - Set or insert the value if the key is not already present. When the cache reached its capacity, it should invalidate the least recently used item before inserting a new item.
Follow up:
Could you do both operations in O(1) time complexity?
Example:
LRUCache cache = new LRUCache( 2 /* capacity */ );

cache.put(1, 1);
cache.put(2, 2);
cache.get(1);       // returns 1
cache.put(3, 3);    // evicts key 2
cache.get(2);       // returns -1 (not found)
cache.put(4, 4);    // evicts key 1
cache.get(1);       // returns -1 (not found)
cache.get(3);       // returns 3
cache.get(4);       // returns 4
  Google Uber Facebook Twitter Zenefits Amazon Microsoft Snapchat Yahoo Bloomberg Palantir

思路: use a hashmap + doubly linked List: (head)..(pre)<—>(cur)<—>(next)..(end)
           Always set the head for the most recent accessed node.
           watch edge case like 1 node in list. Deleting head/tail, we need to set head/tail simultaneously.
Complexity: Time O(1) Space O(N)

public class LRUCache {
    class Node{
        Node pre;
        Node next;
        int val;
        int key;//need key fields for look back to delete in Map
        public Node(int key,int value){
            this.val = value;
            this.key = key;
        }
    }
    private void removeNode(Node n){
        Node preN = n.pre;
        Node nextN = n.next;
        if(n == head)head = nextN;//watch case of deleting head & end
        if(n == end)end = preN;//
        if(preN != null)preN.next = nextN;
        if(nextN != null)nextN.pre = preN;
    }
    public void setHead(Node n){//head is most recent val
        n.next = head;
        n.pre = null;
        if(head != null) head.pre = n;
        head = n;
        if(end == null)end = head;//actually when only head in list
    }
    //instance variable
    Node head = null;
    Node end = null;
    HashMap<Integer,Node> map = new HashMap<>(); //<val, node in list>
    int capacity;
    public LRUCache(int capacity) {
        this.capacity = capacity;
    }
    
    public int get(int key) {
        if(!map.containsKey(key))return -1;
        Node cur = map.get(key);
        removeNode(cur);
        setHead(cur);
        return cur.val;
    }
    
    public void put(int key, int value) {
        if(!map.containsKey(key)){
            if(map.size() >= capacity){
                map.remove(end.key);
                removeNode(end);
            }
            Node cur = new Node(key, value);
            map.put(key, cur);
            setHead(cur);
        }else{//update value
            Node cur = map.get(key);
            cur.val = value;
            removeNode(cur);
            setHead(cur);
        }
    }
}

/**
 * Your LRUCache object will be instantiated and called as such:
 * LRUCache obj = new LRUCache(capacity);
 * int param_1 = obj.get(key);
 * obj.put(key,value);
 */

Sunday, February 12, 2017

Leetcode/G家F家苹果-- 257. Binary Tree Paths(DFS)

257. Binary Tree Paths(dfs)
Easy
Given a binary tree, return all root-to-leaf paths.
For example, given the following binary tree:
   1
 /   \
2     3
 \
  5
All root-to-leaf paths are:
["1->2->5", "1->3"]
思路: use dfs to traverse tree, append val to stringbuilder, add string to res when meeting root.
Complexity: Time: O(n), Space: O(n) -arraylist
way1 - stringbuilder
public List<String> binaryTreePaths(TreeNode root) {
        List<String> res = new ArrayList<>();
        helper(root, res, new StringBuilder());
        return res;
    }
    public void helper(TreeNode root, List<String> res, StringBuilder s){
        if(root == null)return;
        int len = s.length();
        s.append(root.val).append("->");
        if(root.left == null && root.right == null){
            res.add(s.toString().substring(0, s.length()-2));//remove last "->"
        }
        helper(root.left, res, s);
        helper(root.right, res, s);
        s.setLength(len);
    }
way2 - string
public List<String> binaryTreePaths(TreeNode root) {
        List<String> res = new ArrayList<String> ();
        if(root == null){ return res;}
        String cur = new String("");
        addpath(root, res, cur);
        return res;
    }
    private void addpath(TreeNode root,List<String> res,String cur){
        if(root == null){
            return;
        }
        cur += Integer.toString(root.val);
        cur += "->";//string + opperation no need to set back length
        if(root.left==null&&root.right==null){
            cur = cur.substring(0,cur.length()-2);
            res.add(cur);
        }
        addpath(root.left,res,cur);
        addpath(root.right,res,cur);
    }

Leetcode/G家F家 -- 341. Flatten Nested List Iterator (Design + Recur)

341. Flatten Nested List Iterator(Design + Recur)
medium
https://leetcode.com/problems/flatten-nested-list-iterator/
相关题: 同样用recursion traverse list 来计算
http://rainykat.blogspot.com/2017/01/leetcodelinkedin-339364-nested-list.html 
Given a nested list of integers, implement an iterator to flatten it.
Each element is either an integer, or a list -- whose elements may also be integers or other lists.
Example 1:
Given the list [[1,1],2,[1,1]],
By calling next repeatedly until hasNext returns false, the order of elements returned by next should be: [1,1,2,1,1].
Example 2:
Given the list [1,[4,[6]]],
By calling next repeatedly until hasNext returns false, the order of elements returned by next should be: [1,4,6].

思路: traverse the nested list using recursion and store element to arraylist.
/**
 * // This is the interface that allows for creating nested lists.
 * // You should not implement it, or speculate about its implementation
 * public interface NestedInteger {
 *
 *     // @return true if this NestedInteger holds a single integer, rather than a nested list.
 *     public boolean isInteger();
 *
 *     // @return the single integer that this NestedInteger holds, if it holds a single integer
 *     // Return null if this NestedInteger holds a nested list
 *     public Integer getInteger();
 *
 *     // @return the nested list that this NestedInteger holds, if it holds a nested list
 *     // Return null if this NestedInteger holds a single integer
 *     public List<NestedInteger> getList();
 * }
 */
public class NestedIterator implements Iterator<Integer> {
    List<Integer> list = new ArrayList<>();
    int pos = 0;//current position
    public NestedIterator(List<NestedInteger> nestedList) {
        //use arrayList to store nestedList
        traverse(nestedList);
    }
    public void traverse(List<NestedInteger> nestedList){
        if(nestedList == null) return;
        for(NestedInteger e: nestedList){
            if(e.isInteger()){
                list.add(e.getInteger());
            }else{
                traverse(e.getList());//do recursion when meeting list element
            }
        }
    }
    @Override
    public Integer next() {
        return list.get(pos++);
    }

    @Override
    public boolean hasNext() {
        return pos < list.size();
    }
}

/**
 * Your NestedIterator object will be instantiated and called as such:
 * NestedIterator i = new NestedIterator(nestedList);
 * while (i.hasNext()) v[f()] = i.next();
 */

Saturday, February 11, 2017

Leetcode/各大家 -- 10. Regular Expression Matching(DP)

10. Regular Expression Matching(DP)
hard
https://leetcode.com/problems/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
思路: 见图, 1. 事先要把0presense的情况标好
                        2. 填数组,watch几个关键情况
public class Solution {
    public boolean isMatch(String s, String p) {
        boolean[][] dp = new boolean[s.length()+1][p.length()+1];
        dp[0][0] = true;
        //handle 1st row dealing a*b* - 0 presence, mark such * true
        for(int j = 1; j < dp[0].length; j++){
            if(p.charAt(j-1) == '*')
                dp[0][j] = dp[0][j-2];    
        }
        for(int i = 1; i < dp.length; i++){
            for(int j = 1; j < dp[0].length; j++){
                char sc = s.charAt(i-1);
                char pc = p.charAt(j-1);
                if(pc == sc || pc == '.'){
                    dp[i][j] = dp[i-1][j-1];
                }else if(pc == '*'){
                    if(dp[i][j-2]){
                        dp[i][j] = true;//0 presence of pre letter
                    }else if(p.charAt(j-2) == s.charAt(i-1) || p.charAt(j-2) == '.'){
                        dp[i][j] = dp[i-1][j];
                    }
                }
                //both different letter, fill false
            }
        }
        return dp[s.length()][p.length()];
    }
}

Friday, February 10, 2017

Leetcode/各大家-- 380. Insert Delete GetRandom O(1) (Random + Design)

380. Insert Delete GetRandom O(1)
medium
https://leetcode.com/problems/insert-delete-getrandom-o1/
Design a data structure that supports all following operations in average O(1) time.
  1. insert(val): Inserts an item val to the set if not already present.
  2. remove(val): Removes an item val from the set if present.
  3. getRandom: Returns a random element from current set of elements. Each element must have the same probability of being returned.
Example:
// Init an empty set.
RandomizedSet randomSet = new RandomizedSet();

// Inserts 1 to the set. Returns true as 1 was inserted successfully.
randomSet.insert(1);

// Returns false as 2 does not exist in the set.
randomSet.remove(2);

// Inserts 2 to the set, returns true. Set now contains [1,2].
randomSet.insert(2);

// getRandom should return either 1 or 2 randomly.
randomSet.getRandom();

// Removes 1 from the set, returns true. Set now contains [2].
randomSet.remove(1);

// 2 was already in the set, so return false.
randomSet.insert(2);

// Since 2 is the only number in the set, getRandom always return 2.
randomSet.getRandom();
思路:Use HashMap + ArrayList to build the data structure.
          Map store pairs of <val, index in list> and List is store the val existed.
          They are same size. Add and remove together
          When removal, list: replace the removed element with last added element.
                                    map: replace the index(val) of last added element, and remove val(key)

Complexity: Space: O(N)

ublic class RandomizedSet {
    Map<Integer, Integer> map;//<val, index in arrlist>
    List<Integer> list;//keep a record of value for get random 
    int size;//map and list are the same size
    Random rand;
    /** Initialize your data structure here. */
    public RandomizedSet() {
        this.map = new HashMap<>();
        this.list = new ArrayList<>();
        this.size = 0;
        this.rand = new Random();
    }
    
    /** Inserts a value to the set. Returns true if the set did not already contain the specified element. */
    public boolean insert(int val) {
        if(map.containsKey(val)) return false;
        map.put(val, size);
        list.add(val);
        size++;
        return true;
    }
    
    /** Removes a value from the set. Returns true if the set contained the specified element. */
    public boolean remove(int val) {
        if(map.containsKey(val)){
            int last = list.get(size - 1);
            list.set(map.get(val), last);//use last added ele to fill the element to be removed 
            map.put(last, map.get(val));//update last added ele's index in list
            map.remove(val);
            list.remove(size - 1);//remove at end is constant
            size--;
            return true;
        }
        return false;
    }
    
    /** Get a random element from the set. */
    public int getRandom() {
        return list.get(rand.nextInt(size));
    }
}

/**
 * Your RandomizedSet object will be instantiated and called as such:
 * RandomizedSet obj = new RandomizedSet();
 * boolean param_1 = obj.insert(val);
 * boolean param_2 = obj.remove(val);
 * int param_3 = obj.getRandom();
 */