Tuesday, June 16, 2015

Day 108, ##,Add and Search Word - Data structure design, House Robber II, Shortest Palindrome

Add and Search Word - Data structure design
Design a data structure that supports the following two operations:
void addWord(word)
bool search(word)
search(word) can search a literal word or a regular expression string containing only letters a-z or .. A . means it can represent any one letter.
For example:
addWord("bad")
addWord("dad")
addWord("mad")
search("pad") -> false
search("bad") -> true
search(".ad") -> true
search("b..") -> true
Note:
You may assume that all words are consist of lowercase letters a-z.
--------------------------------------------------------------
Trie,
class TrieNode {
public:
    vector<TrieNode *> children;
    bool end;
    TrieNode() {
        end = false;
        children = vector<TrieNode *>(26,NULL);
    }
};

class WordDictionary {
public:
    WordDictionary() {
        root = new TrieNode();
    }
    
    // Adds a word into the data structure.
    void addWord(string word) {
        TrieNode *itr = root;
        for (int i = 0; i < word.length(); i++) {
            if (itr->children[word[i] - 'a'] == NULL) {
                itr->children[word[i] - 'a'] = new TrieNode();
            }
            itr = itr->children[word[i] - 'a'];
        }
        itr->end = true;
    }

    bool searchHelper(string word, int index,TrieNode *itr) {
        if (index == word.length()) return itr->end;
        if (word[index] != '.') {
            TrieNode* t = itr->children[word[index] - 'a']; 
            if (t != NULL) {
                return searchHelper(word,index + 1, t);
            }
            return false;
        }
        
        for (int i = 0; i < 26; i++) {
            TrieNode* t = itr->children[i]; 
            if (t != NULL && searchHelper(word,index + 1, t)) {
                return true;
            }
        }
        
        return false;
    }

    // Returns if the word is in the data structure. A word could
    // contain the dot character '.' to represent any one letter.
    bool search(string word) {
        return searchHelper(word,0,root);
    }
private:
    TrieNode* root;
};

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


Java, addWord可以用for循环,也可以递归。searchWord的时候只能递归了,因为遇到‘.’得尝试所有26位,然后backtrace
class WordDictionary {
    
    private Node root;

    /** Initialize your data structure here. */
    public WordDictionary() {
        root = new Node('0');
    }
    
    /** Adds a word into the data structure. */
    public void addWord(String word) {
        
        Node itr = root;
        for (int i = 0; i < word.length(); i++) {
            char c = word.charAt(i);
            if (!itr.letters.containsKey(c)){
                itr.letters.put(c, new Node(c));
            }
            
            if (i == word.length() - 1) {
                itr.letters.get(c).isWord = true;
            }
            
            itr = itr.letters.get(c);
        }
        
    }
    
    /** Returns if the word is in the data structure. A word could contain the dot character '.' to represent any one letter. */
    public boolean search(String word) {
        
        return helper(word, 0, root);
    }
    
    private boolean helper(String word, int index, Node node) {
        
        if (index == word.length()) {
            return node.isWord;
        }
        
        char c = word.charAt(index);
        if (node.letters.containsKey(c)) {
            if (helper(word, index + 1, node.letters.get(c))) return true;
        }else if (c == '.') {
            for (Map.Entry entry : node.letters.entrySet()) {
                if (helper(word, index + 1, entry.getValue())) {
                    return true;
                }
            }
        }
        
        return false;
        
    }
}

class Node{
    public char c;
    public Map letters;
    public boolean isWord;
    
    public Node(char c) {
        this.c = c;
        letters = new HashMap();
        isWord = false;
    }
}

/**
 * Your WordDictionary object will be instantiated and called as such:
 * WordDictionary obj = new WordDictionary();
 * obj.addWord(word);
 * boolean param_2 = obj.search(word);
 */
Word Search II
Given a 2D board and a list of words from the dictionary, find all words in the board.
Each word must be constructed from letters of sequentially adjacent cell, where "adjacent" cells are those horizontally or vertically neighboring. The same letter cell may not be used more than once in a word.
For example,
Given words = ["oath","pea","eat","rain"] and board =
[
  ['o','a','a','n'],
  ['e','t','a','e'],
  ['i','h','k','r'],
  ['i','f','l','v']
]
Return ["eat","oath"].
Note:
You may assume that all inputs are consist of lowercase letters a-z.
You would need to optimize your backtracking to pass the larger test. Could you stop backtracking earlier?
If the current candidate does not exist in all words' prefix, you could stop backtracking immediately. What kind of data structure could answer such query efficiently? Does a hash table work? Why or why not? How about a Trie? If you would like to learn how to implement a basic trie, please work on this problem: Implement Trie (Prefix Tree) first.
----------------------------------------------------
Used prefix tree from the previous question
class TrieNode {
public:
    TrieNode() {
        next = vector<TrieNode*>(26,NULL);
        terminal = false;
    }
 
    char value;
    vector<TrieNode*> next;
    bool terminal;
};

class Trie {
public:
    Trie() {
        root = new TrieNode();
    }
 
    // Inserts a word into the trie.
    void insert(string s) {
        TrieNode *cur = root;
        for (int i = 0; i < s.length(); i++) {
            char c = s[i] - 'a';
            if (cur->next[c] == NULL) {
                TrieNode *trie = new TrieNode();
                trie->value = c;
                cur->next[c] = trie;
            }
            cur = cur->next[c];
        }
        cur->terminal = true;
    }
 
    // Returns if the word is in the trie.
    bool search(string key) {
        TrieNode *cur = root;
        for (int i = 0; i < key.length(); i++) {
            char c = key[i] - 'a';
            if (cur->next[c] == NULL) {
                return false;
            }
             
            cur = cur->next[c];
        }
         
        return cur->terminal;
    }
 
    // Returns if there is any word in the trie
    // that starts with the given prefix.
    bool startsWith(string prefix) {
        TrieNode *cur = root;
        for (int i = 0; i < prefix.length(); i++) {
            char c = prefix[i] - 'a';
            if (cur->next[c] == NULL) {
                return false;
            }
             
            cur = cur->next[c];
        }
         
        return true;
    }
private:
    TrieNode* root;
};

class Solution {
public:
    void search(vector<string> &rt, vector<vector<char>>& board, 
            vector<vector<bool> > &visit, Trie &trie, string word, int row, int col, unordered_set<string> &hadIt) {
        if (row < 0 || row >= board.size() || col < 0 || col >= board[0].size() || visit[row][col]) {
            return;
        }
        word += board[row][col];
        visit[row][col] = true;
        if (hadIt.find(word) == hadIt.end() && trie.search(word)) {
            hadIt.insert(word);
            rt.push_back(word);
        }
        
        if (trie.startsWith(word)) {
            search(rt,board,visit,trie,word,row + 1,col,hadIt);
            search(rt,board,visit,trie,word,row - 1,col,hadIt);
            search(rt,board,visit,trie,word,row,col + 1,hadIt);
            search(rt,board,visit,trie,word,row,col - 1,hadIt);
        }
        visit[row][col] = false;
    }

    vector<string> findWords(vector<vector<char>>& board, vector<string>& words) {
        Trie trie;
        for (int i = 0; i < words.size(); i++) {
            trie.insert(words[i]);
        }
        
        vector<string> rt;
        vector<vector<bool> > visit(board.size(),vector<bool>(board[0].size(),false));
        unordered_set<string> hadIt;
        for (int i = 0; i < board.size(); i++) {
            for (int j = 0; j <board[0].size(); j++) {
                search(rt,board,visit,trie,"",i,j,hadIt);
            }
        }
        
        return rt;
    }
};

House Robber II
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.
----------------------------------------------
看了答案!
class Solution {
public:
    int robHelper(vector<int>& nums, int left, int right) {
        int pre_1 = 0, pre_2 = 0, pre_3 = 0;
        for (int i = left; i <= right; i++) {
            int temp = pre_3;
            pre_3 = max(pre_3,max(pre_1,pre_2) + nums[i]);
            pre_1 = pre_2;
            pre_2 = temp;
        }
        
        return pre_3;
    }

    int rob(vector<int>& nums) {
        if (nums.size() == 0) return 0;
        if (nums.size() == 1) return nums[0];
        return max(robHelper(nums,0,nums.size() - 2),robHelper(nums,1,nums.size() - 1));
    }
};

Shortest Palindrome
Given a string S, you are allowed to convert it to a palindrome by adding characters in front of it. Find and return the shortest palindrome you can find by performing this transformation.
For example:
Given "aacecaaa", return "aaacecaaa".
Given "abcd", return "dcbabcd".
---------------------------------------------------------------
O(n^2) 找prefix是palindrome。超时
class Solution {
public:
    bool isPalindrome(string s) {
        for (int i = 0; i < s.length() / 2; i++) {
            if (s[i] != s[s.length() - 1 - i]) return false;
        }
        
        return true;
    }
    
    int longestPal(string s) {
        for (int i = s.length(); i > 0; i--) {
            if (isPalindrome(s.substr(0,i))) {
                return i;
            }
        }
        
        return 0;
    }
    
    string shortestPalindrome(string s) {
        int length = longestPal(s);
        string copy = s;
        for (int i = 0; i < copy.length() - length; i++) {
            s = copy[length + i] + s;    
        }
        
        return s;
    }
};
看了答案!对KMP要灵活运用
s + special char + reverse(s)
然后运用KMP的failure function计算出s的prefix和revsers(s)的suffix相等的最长长度
ref: https://leetcode.com/discuss/36807/c-8-ms-kmp-based-o-n-time-%26-o-n-memory-solution
class Solution {
public:
    vector<int> computePrefixTable(string pattern) {
        int m = pattern.length();
        vector<int> table(m,0);
        int matchedLength = 0;
        
        for (int i = 1; i < m; i++) {
            // until find the next char at matchedLength is equal to char at i
            // or matchedLength is zero
            while (matchedLength > 0 && pattern[matchedLength] != pattern[i]) {
                matchedLength = table[matchedLength - 1];
            }
            if (pattern[matchedLength] == pattern[i]) {
                matchedLength++;
            }
            table[i] = matchedLength;
        }
        
        return table;
    }
    string shortestPalindrome(string s) {
        string rev = s;
        reverse(rev.begin(),rev.end());
        string pattern = s + "*" + rev;
        vector<int> table = computePrefixTable(pattern);
        
        return rev.substr(0,rev.length() - table[table.size() - 1]) + s;
    }
};

Sunday, June 14, 2015

Day 107, ##, Minimum Size Subarray Sum, Course Schedule II

Minimum Size Subarray Sum
Given an array of n positive integers and a positive integer s, find the minimal length of a subarray of which the sum ≥ s. If there isn't one, return 0 instead.
For example, given the array [2,3,1,2,4,3] and s = 7,
the subarray [4,3] has the minimal length under the problem constraint.
More practice:
If you have figured out the O(n) solution, try coding another solution of which the time complexity is O(n log n).
-------------------------------------------------------
Sliding window, O(n)

class Solution {
public:
    int minSubArrayLen(int s, vector<int>& nums) {
        if (nums.size() == 0) return 0;
        int minLen = INT_MAX;
        int right = 0, left = 0;
        
        int sum = nums[right];
        while (right < nums.size()) {
            if (sum < s) {
                right++;
                sum += nums[right];
            }else {
                minLen = min(right - left + 1, minLen);
                sum -= nums[left];
                left++;
            }
        }
        
        if (minLen == INT_MAX) return 0;
        return minLen;
    }
};
O(NlogN),
sums[i]计算了nums[0 : i + 1]的连续值,所以sums内的值是递增,由此可以用binary search
所求的最短subarray就是计算 sums[i] + s >= sums[j], j取[1: ]
注意各variable的取值
binary()返回的值可能会等于 sums.size(),


class Solution {
public:
    int binary(int s, vector<int> &sums, int left) {
        int right = sums.size() - 1;
        int minLen = INT_MAX;
        int sum = 0;
        
        while (left <= right) {
            int mid = left + (right - left) / 2; 
            if (sums[mid] >= s) {
                right = mid - 1;
            }else {
                left = mid + 1;
            }
        }
        
        return left;
    }

    int minSubArrayLen(int s, vector<int>& nums) {
        if (nums.size() == 0) return 0;
        int minLen = INT_MAX;
        
        vector<int> sums(nums.size() + 1,0);
        for (int i = 1; i <= nums.size(); i++) {
            sums[i] = sums[i - 1] + nums[i - 1];
        }
        
        for (int i = 0; i < nums.size(); i++) {
            int end = binary(s + sums[i - 1],sums,i);
            if (end == sums.size()) break;
            minLen = min(end - i + 1, minLen);
        }
        
        if (minLen == INT_MAX) return 0;
        return minLen;
    }
};

Java O(n)版本
class Solution {
    public int minSubArrayLen(int s, int[] nums) {
        int n = nums.length;
        int start = 0;
        int minLen = n + 1;
        int sum = 0;
        
        for (int i = 0; i < n; i++) {
            sum += nums[i];
            
            while (sum >= s) {
                minLen = Math.min(minLen, i - start + 1);
                sum -= nums[start];
                start++;
            }
        }
        
        return minLen > n ? 0 : minLen;
    }
}
Course Schedule 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, return the ordering of courses you should take to finish all courses.
There may be multiple correct orders, you just need to return one of them. If it is impossible to finish all courses, return an empty array.
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 the correct course order is [0,1]
4, [[1,0],[2,0],[3,1],[3,2]]
There are a total of 4 courses to take. To take course 3 you should have finished both courses 1 and 2. Both courses 1 and 2 should be taken after you finished course 0. So one correct course order is [0,1,2,3]. Another correct ordering is[0,2,1,3].
Note:
The input prerequisites is a graph represented by a list of edges, not adjacency matrices. Read more about how a graph is represented.
Hints:
  1. This problem is equivalent to finding the topological order in a directed graph. If a cycle exists, no topological ordering exists and therefore it will be impossible to take all courses.
  2. Topological Sort via DFS - A great video tutorial (21 minutes) on Coursera explaining the basic concepts of Topological Sort.
  3. Topological sort could also be done via BFS.
-----------------------------------------------------
topological sort, 考虑cycle问题
DFS
class Solution {
public:
    bool dfs(vector<vector<int>> &edges,int course,vector<int> &visit,vector<int> &path) {
        if (visit[course] == -1) return false;
        if (visit[course] == 1) return true;
        visit[course] = -1;
        
        for (int i = 0; i < edges[course].size(); i++) {
            if (!dfs(edges,edges[course][i],visit,path)) return false;
        }
        path.push_back(course);
        visit[course] = 1;
        return true;
    }

    vector<int> findOrder(int numCourses, vector<pair<int, int>>& prerequisites) {
        vector<vector<int>> edges(numCourses,vector<int>());
        vector<int> path;
        vector<int> visit(numCourses,0);    
        
        for (int i = 0; i < prerequisites.size(); i++) {
            edges[prerequisites[i].second].push_back(prerequisites[i].first);
        }
        for (int i = 0; i < numCourses; i++) {
            if (!dfs(edges,i,visit,path)) {
                vector<int> rt;
                return rt;
            }
        }
        reverse(path.begin(),path.end());
        return path;
    }
};
BFS
ref: https://en.wikipedia.org/wiki/Topological_sorting#Algorithms
class Solution {
public:
    vector<int> findOrder(int numCourses, vector<pair<int, int>>& prerequisites) {
        vector<vector<int> > edges(numCourses);
        vector<int> order;
        vector<int> inDegree(numCourses,0);
        queue<int> que;
        
        for (int i = 0; i < prerequisites.size(); i++) {
            edges[prerequisites[i].second].push_back(prerequisites[i].first);
            inDegree[prerequisites[i].first]++;
        }
        
        for (int i = 0; i < numCourses; i++) {
            if (inDegree[i] == 0) {
                que.push(i);
            }
        }
        
        while (!que.empty()) {
            int current = que.front();
            que.pop();
            order.push_back(current)
            ;
            for (int i = 0; i < edges[current].size(); i++) {
                int neighbor = edges[current][i];
                inDegree[neighbor]--;
                if (inDegree[neighbor] == 0) {
                    que.push(neighbor);
                }
            }
        }
        
        for (int i = 0; i < numCourses; i++) {
            if (inDegree[i] != 0) {
                order = vector<int>();
                return order;
            }
        }
        
        return order;
    }
};

Saturday, June 13, 2015

To do


  1. topological ordering: BFS
  2. trie
  3. compiler stuff, context-free grammar, string parsing, state-machine
  4. web crawler
  5. KMP
  6. Rolling Hash
  7. 树,打印所有距离leef node为k的节点,或者打印所有距离为某一个节点为k的所有节点
  8. combination, complexity
  9. find peak elem II, http://courses.csail.mit.edu/6.006/spring11/lectures/lec02.pdfhttp://courses.csail.mit.edu/6.006/spring11/rec/rec02.pdf
  10. 约瑟夫环
  11. game theory
  12. 可改变下思路, 有时候pass by reference + void 可变为直接返回一个有效值(如 int)
  13. Binomial theorem
  14. bloom filter简单解释:http://billmill.org/bloomfilter-tutorial/
  15. 平面上最远的2个点, http://noalgo.info/799.html
  16. Best Time to Buy and Sell Stock IV
  17. 在stream里面,找top k个最常出现的词  http://stackoverflow.com/questions/3260653/algorithm-to-find-top-10-search-terms?newreg=e0d277c9365f499fbf54de491a7b1d1f

Friday, June 12, 2015

Day 106, ##, Course Schedule, Implement Trie (Prefix Tree)

Course Schedule
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.
Note:
The input prerequisites is a graph represented by a list of edges, not adjacency matrices. Read more about how a graph is represented.
Hints:
  1. This problem is equivalent to finding if a cycle exists in a directed graph. If a cycle exists, no topological ordering exists and therefore it will be impossible to take all courses.
  2. Topological Sort via DFS - A great video tutorial (21 minutes) on Coursera explaining the basic concepts of Topological Sort.
  3. Topological sort could also be done via BFS.
-------------------------------------------------------------
重点:缺乏知识点,topological ordering的BFS做法https://en.wikipedia.org/wiki/Topological_sorting#Algorithms
Detect if there is a cycle in directed graph,
BFS
class Solution {
public:
    bool canFinish(int numCourses, vector<pair<int, int>>& prerequisites) {
        vector<vector<int> > edges(numCourses);
        vector<int> inDegree(numCourses,0);
        queue<int> que;
         
        for (int i = 0; i < prerequisites.size(); i++) {
            edges[prerequisites[i].second].push_back(prerequisites[i].first);
            inDegree[prerequisites[i].first]++;
        }
        
        for (int i = 0; i < numCourses; i++) {
            if (inDegree[i] == 0) {
                que.push(i);
            }
        }
        
        while (!que.empty()) {
            int current = que.front();
            que.pop();
            for (int i = 0; i < edges[current].size(); i++) {
                inDegree[edges[current][i]]--;
                if (inDegree[edges[current][i]] == 0) {
                    que.push(edges[current][i]);
                }
            }
        }
        
        for (int i = 0; i < numCourses; i++) {
            if (inDegree[i] != 0) {
                return false;
            }
        }
        
        return true;
    }
};

DFS
class Solution {
public:
    bool dfs(vector<vector<int> > &edges, vector<int> &visit, int point) {
        if (visit[point] == -1) return false;
        if (visit[point] == 1) return true;
        
        visit[point] = -1;
        for (int i = 0; i < edges[point].size(); i++) {
            if (!dfs(edges,visit,edges[point][i])) {
                return false;
            }
        }
        visit[point] = 1;
        return true;
    }

    bool canFinish(int numCourses, vector<pair<int, int>>& prerequisites) {
        vector<int> visit(numCourses,0);
        vector<vector<int> > edges(numCourses);
        
        for (int i = 0; i < prerequisites.size(); i++) {
            edges[prerequisites[i].second].push_back(prerequisites[i].first);
        }
        
        for (int i = 0; i < numCourses; i++) {
            if (!dfs(edges,visit,i)) return false;
        }
        
        return true;
    }
};

Java, updated on Sep-29th-2018
class Solution {
    
    public boolean canFinish(int numCourses, int[][] prerequisites) {
        List<List<Integer>> graph = builtGraph(numCourses, prerequisites);
        int[] visited = new int[numCourses];
        
        for (int i = 0; i < numCourses; i++) {
            if (!dfs(graph, i, visited)) return false;
        }
        
        return true;
    }
    
    private boolean dfs(List<List<Integer>> graph, int num, int[] visited) {
        if (visited[num] == 1) return true;
        if (visited[num] == -1) return false;
        
        visited[num] = -1;
        for (int nei : graph.get(num)) {
            if (!dfs(graph, nei, visited)) return false;
        }
        
        visited[num] = 1;
        return true;
    }
    
    private List<List<Integer>> builtGraph(int numCourses, int[][] prerequisites) {
        List<List<Integer>> rt = new ArrayList<>();
        for (int i = 0; i < numCourses; i++) {
            rt.add(new ArrayList<>());
        }
        
        for (int[] edge : prerequisites) {
            rt.get(edge[1]).add(edge[0]);
        }
        
        return rt;
    }

}

BFS, Java
O(n), n是edge的数量,复杂度跟DFS一样
class Solution {
    
    public boolean canFinish(int numCourses, int[][] prerequisites) {
        List<List<Integer>> rt = new ArrayList<>();
        int[] inEdges = new int[numCourses];
        for (int i = 0; i < numCourses; i++) {
            rt.add(new ArrayList<>());
        }
        
        for (int[] edge : prerequisites) {
            rt.get(edge[1]).add(edge[0]);
            inEdges[edge[0]]++;
        }
        
        Queue<Integer> que = new LinkedList<>();
        int count = 0;
        for (int i = 0; i < numCourses; i++) {
            if (inEdges[i] == 0) {
                que.add(i);
            }
        }
        
        while (!que.isEmpty()) {
            int top = que.poll();
            for (int i : rt.get(top)) {
                inEdges[i]--;
                count++;
                if (inEdges[i] == 0) {
                    que.add(i);
                }
            }
        }
        
        return count == prerequisites.length;
    }
}

Implement Trie (Prefix Tree)
Implement a trie with insertsearch, and startsWith methods.
Note:
You may assume that all inputs are consist of lowercase letters a-z.
---------------------------------------------
在判断terminal上代码可以更简化
class TrieNode {
public:
    
    // Initialize your data structure here.
    TrieNode() {
        next = vector<TrieNode*>(26,NULL);
        terminal = false;
    }

    char value;
    vector<TrieNode*> next;
    bool terminal;
};

class Trie {
public:
    Trie() {
        root = new TrieNode();
    }

    // Inserts a word into the trie.
    void insert(string s) {
        TrieNode *cur = root;
        for (int i = 0; i < s.length(); i++) {
            char c = s[i] - 'a';
            if (cur->next[c] == NULL) {
                TrieNode *trie = new TrieNode();
                trie->value = c;
                cur->next[c] = trie;
            }
            if (i == s.length() - 1) {
             cur->next[c]->terminal = true;
            }
            cur = cur->next[c];
        }
    }

    // Returns if the word is in the trie.
    bool search(string key) {
        TrieNode *cur = root;
        for (int i = 0; i < key.length(); i++) {
            char c = key[i] - 'a';
            if (cur->next[c] == NULL) {
                return false;
            }
            if (i == key.length() - 1 && cur->next[c]->terminal) {
                return true;
            } 
            
            cur = cur->next[c];
        }
        
        return false;
    }

    // Returns if there is any word in the trie
    // that starts with the given prefix.
    bool startsWith(string prefix) {
        TrieNode *cur = root;
        for (int i = 0; i < prefix.length(); i++) {
            char c = prefix[i] - 'a';
            if (cur->next[c] == NULL) {
                return false;
            }
            
            cur = cur->next[c];
        }
        
        return true;
    }

private:
    TrieNode* root;
};

// Your Trie object will be instantiated and called as such:
// Trie trie;
// trie.insert("somestring");
// trie.search("key");

Java, updated on July-8th-2018
class Trie {
    class Node{
        public Map<Character, Node> next;
        public boolean isWord;
        public Node() {
            next = new HashMap<>();    
        }
    }
    
    private Node root;
    /** Initialize your data structure here. */
    public Trie() {
        root = new Node();
    }
    
    /** Inserts a word into the trie. */
    public void insert(String word) {
        Node node = root;
        for (int i = 0; i < word.length(); i++) {
            char c = word.charAt(i);
            if (!node.next.containsKey(c)) {
                node.next.put(c, new Node());
            }
            node = node.next.get(c);
        }
        node.isWord = true;
    }
    
    /** Returns if the word is in the trie. */
    public boolean search(String word) {
        Node node = getThatNode(word);
        return node != null && node.isWord;
    }
    
    /** Returns if there is any word in the trie that starts with the given prefix. */
    public boolean startsWith(String prefix) {
        return getThatNode(prefix) != null;
    }
    
    private Node getThatNode(String word) {
        Node node = root;
        for (int i = 0; i < word.length(); i++) {
            char c = word.charAt(i);
            if (!node.next.containsKey(c)) return null;
            node = node.next.get(c);
        }
        
        return node;
    }
}

/**
 * Your Trie object will be instantiated and called as such:
 * Trie obj = new Trie();
 * obj.insert(word);
 * boolean param_2 = obj.search(word);
 * boolean param_3 = obj.startsWith(prefix);
 */

Thursday, June 11, 2015

Day 105, ##, Binary Tree Right Side View, Number of Islands , Bitwise AND of Numbers Range, Happy Number, Remove Linked List Elements, Isomorphic Strings

Binary Tree Right Side View 
Given a binary tree, imagine yourself standing on the right side of it, return the values of the nodes you can see ordered from top to bottom.
For example:
Given the following binary tree,
   1            <---
 /   \
2     3         <---
 \     \
  5     4       <---
You should return [1, 3, 4].
-------------------------------------------------------
Similar to level order traversal
can be done iteratively with a queue

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    void side(vector<int> &rt, int level, TreeNode *root) {
        if (root == NULL) {
            return;
        }
        
        if (rt.size() < level) {
            rt.push_back(root->val);
        }else {
            rt[level - 1] = root->val;
        }
        
        side(rt,level + 1, root->left);
        side(rt,level + 1, root->right);
    }

    vector<int> rightSideView(TreeNode* root) {
        vector<int> rt;
        side(rt,1,root);
        return rt;
    }
};

Number of Islands
Given a 2d grid map of '1's (land) and '0's (water), count the number of islands. An island is surrounded by water and is formed by connecting adjacent lands horizontally or vertically. You may assume all four edges of the grid are all surrounded by water.
Example 1:
11110
11010
11000
00000
Answer: 1
Example 2:
11000
11000
00100
00011
Answer: 3
------------------------------------------------------
Solution #1 dfs
class Solution {
public:
    void dfs(vector<vector<char>>& grid, vector<vector<bool> > &visit, int row, int col) {
        if (row < 0 || row >= visit.size() || col < 0 || col >= visit[0].size() || visit[row][col] || grid[row][col] == '0') return;
        
        visit[row][col] = true;
        dfs(grid,visit,row + 1, col);
        dfs(grid,visit,row - 1, col);
        dfs(grid,visit,row, col + 1);
        dfs(grid,visit,row, col - 1);
    }

    int numIslands(vector<vector<char>>& grid) {
        int m = grid.size();
        if (m == 0) return 0;
        int n = grid[0].size();
        vector<vector<bool> > visit(m,vector<bool>(n,false));
        int count = 0;
        
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                if (!visit[i][j] && grid[i][j] == '1') {
                    count++;
                    dfs(grid,visit,i,j);
                }
                
            }
        }
        
        return count;
    }
};
Solution #2 bfs
class Solution {
public:
    void bfs(vector<vector<char>>& grid, vector<vector<bool> > &visit, int row, int col) {
        queue<pair<int,int> > que;
        que.push(make_pair(row,col));
        visit[row][col] = true;
        
        while (!que.empty()) {
            pair<int,int> point = que.front();
            que.pop();
            row = point.first;
            col = point.second;
            
            if (row + 1 < visit.size() && !visit[row + 1][col] && grid[row + 1][col] == '1') {
                que.push(make_pair(row + 1,col));
                visit[row + 1][col] = true;
            }
            
            if (row - 1 >= 0 && !visit[row - 1][col] && grid[row - 1][col] == '1') {
                que.push(make_pair(row - 1,col));
                visit[row - 1][col] = true;
            }
            
            if (col - 1 >= 0 && !visit[row][col - 1] && grid[row][col - 1] == '1') {
                que.push(make_pair(row,col - 1));
                visit[row][col - 1] = true;
            }
            
            if (col + 1 < visit[0].size() && !visit[row][col + 1] && grid[row][col + 1] == '1') {
                que.push(make_pair(row,col + 1));
                visit[row][col + 1] = true;
            }
        }
    }

    int numIslands(vector<vector<char>>& grid) {
        int m = grid.size();
        if (m == 0) return 0;
        int n = grid[0].size();
        vector<vector<bool> > visit(m,vector<bool>(n,false));
        int count = 0;
        
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                if (!visit[i][j] && grid[i][j] == '1') {
                    bfs(grid,visit,i,j);
                    count++;
                }
            }
        }
        
        return count;
    }
};

Bitwise AND of Numbers Range
Given a range [m, n] where 0 <= m <= n <= 2147483647, return the bitwise AND of all numbers in this range, inclusive.
For example, given the range [5, 7], you should return 4.
---------------------------------------
The idea is very simple:
  1. last bit of (odd number & even number) is 0.
  2. when m != n, There is at least an odd number and an even number, so the last bit position result is 0.
  3. Move m and n rigth a position.
Keep doing step 1,2,3 until m equal to n, use a factor to record the iteration time.
class Solution {
public:
    int rangeBitwiseAnd(int m, int n) {
        int count = 0;
        while (m != n) {
            m >>= 1;
            n >>= 1;
            count++;
        }
        
        return m << count;
    }
};
Happy Number
Write an algorithm to determine if a number is "happy".
A happy number is a number defined by the following process: Starting with any positive integer, replace the number by the sum of the squares of its digits, and repeat the process until the number equals 1 (where it will stay), or it loops endlessly in a cycle which does not include 1. Those numbers for which this process ends in 1 are happy numbers.
Example: 19 is a happy number
  • 12 + 92 = 82
  • 82 + 22 = 68
  • 62 + 82 = 100
  • 12 + 02 + 02 = 1
----------------------------------------------
class Solution {
public:
    bool isHappy(int n) {
        unordered_set<int> s;
        
        while (s.find(n) == s.end()) {
            if (n == 1) return true;
            s.insert(n);
            
            int sum = 0;
            while (n != 0) {
                sum += (n % 10) * (n % 10);
                n /= 10;
            }
            n = sum;
        }
        
        return false;
    }
};

Remove Linked List Elements
Remove all elements from a linked list of integers that have value val.
Example
Given: 1 --> 2 --> 6 --> 3 --> 4 --> 5 --> 6, val = 6
Return: 1 --> 2 --> 3 --> 4 --> 5
--------------------------------------------------------
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode* removeElements(ListNode* head, int val) {
        ListNode *dummy = new ListNode(0);
        dummy->next = head;
        ListNode *itr = dummy;
        
        while (itr->next != NULL) {
            if (itr->next->val == val) {
                itr->next = itr->next->next;
            }else {a
                itr = itr->next;
            }
        }
        
        return dummy->next;
    }
};

Isomorphic Strings
Given two strings s and t, determine if they are isomorphic.
Two strings are isomorphic if the characters in s can be replaced to get t.
All occurrences of a character must be replaced with another character while preserving the order of characters. No two characters may map to the same character but a character may map to itself.
For example,
Given "egg""add", return true.
Given "foo""bar", return false.
Given "paper""title", return true.
Note:
You may assume both s and t have the same length.
--------------------------------------------
class Solution {
public:
    bool isIsomorphic(string s, string t) {
        vector<char> dicS(256,'\0');
        vector<char> dicT(256,'\0');
        
        for (int i = 0; i < s.length(); i++) {
            if (dicS[s[i]] == '\0' && dicT[t[i]] == '\0') {
                dicS[s[i]] = t[i];
                dicT[t[i]] = s[i];
            }else if (dicS[s[i]] != t[i] || dicT[t[i]] != s[i]) {
                return false;
            }    
        }
        
        return true;
    }
};

Reverse Linked List
Reverse a singly linked list. 
----------------------------------------------------------------
Iterative
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode* reverseList(ListNode* head) {
        ListNode *newHead = NULL;
        while (head != NULL) {
            ListNode *temp = head->next;
            head->next = newHead;
            newHead = head;
            head = temp;
        }
        
        return newHead;
    }
};
Recursive
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode *rev(ListNode* head, ListNode * newHead) {
        if (head == NULL) return newHead;
        ListNode *temp = head->next;
        head->next = newHead;
        return rev(temp,head);
    }

    ListNode* reverseList(ListNode* head) {
        return rev(head,NULL);
    }
};

Wednesday, June 10, 2015

Day 104, ##, Best Time to Buy and Sell Stock IV, Count Primes, Rotate Array,Reverse Bits, Number of 1 Bits, House Robber

Best Time to Buy and Sell Stock IV
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 at most k transactions.
Note:
You may not engage in multiple transactions at the same time (ie, you must sell the stock before you buy again).
Credits:
Special thanks to @Freezen for adding this problem and creating all test cases.
-----------------------------------------------------------------------------
Solution #1, global[i][j] has the max profit at at most j transaction in i days, local[i][j] has the max profit at at most j transaction in i + 1 days and the last transaction must sell at ith day

local[i][j] = max(global[i -1][j - 1] + max(diff,0), local[i - 1][j] + diff)
global[i][j] = max(global[i - 1][j],local[i][j])

local[i - 1][j] + diff推导:
prices[i] - prices[i - 2] = (prices[i - 1] - prices[i - 2]) + (prices[i] - prices[i - 1])
reference: http://blog.csdn.net/linhuanmars/article/details/23236995

class Solution {
public:
    int maxProfit(int k, vector<int>& prices) {
        if (prices.size() == 0 || k == 0) return 0;
        if (k > prices.size()) {
            return basicSol(prices);
        }
        
        vector<vector<int> > local(prices.size(),vector<int>(k + 1,0));
        vector<vector<int> > global(prices.size(),vector<int>(k + 1,0));
        
        for (int i = 1; i < prices.size(); i++) {
            for (int j = 1; j <= k; j++) {
                int diff = prices[i] - prices[i - 1];
                local[i][j] = max(global[i -1][j - 1] + max(diff,0), local[i - 1][j] + diff);
                global[i][j] = max(global[i - 1][j],local[i][j]);
            }
        }
        
        return global[prices.size() - 1][k];
    }
    
    int basicSol(vector<int>& prices) {
        int res = 0;
        for (int i = 1; i < prices.size(); i++) {
            res += max(0,prices[i] - prices[i - 1]);
        }
        return res;
    }
    
};

Solution #2, space optimization
'cause of global[j - 1], inner loop goes backwards
class Solution {
public:
    int maxProfit(int k, vector<int>& prices) {
        if (prices.size() == 0 || k == 0) return 0;
        if (k > prices.size()) {
            return basicSol(prices);
        }
        
        vector<int> local(k + 1,0);
        vector<int> global(k + 1,0);
        
        for (int i = 1; i < prices.size(); i++) {
            int diff = prices[i] - prices[i - 1];
            for (int j = k; j > 0; j--) {
                local[j] = max(global[j - 1] + max(diff,0), local[j] + diff);
                global[j] = max(global[j],local[j]);
            }
        }
        
        return global[k];
    }
    
    int basicSol(vector<int>& prices) {
        int res = 0;
        for (int i = 1; i < prices.size(); i++) {
            res += max(0,prices[i] - prices[i - 1]);
        }
        return res;
    }
    
};

Count Primes
Description:
Count the number of prime numbers less than a non-negative number, n.
---------------------------------------------------------------------------
details is on OJ
class Solution {
public:
    int countPrimes(int n) {
        vector<bool> isPrime(n, true);
        
        for (int i = 2; i * i < n; i++) {
            if (!isPrime[i]) continue;
            for (int j = i * i; j < n; j += i) {
                isPrime[j] = false;
            }
        }
        
        int count = 0;
        for (int i = 2; i < n; i++) {
            if (isPrime[i]) {
                count++;
            }
        }
        
        return count;
    }
};
Rotate Array
Rotate an array of n elements to the right by k steps.
For example, with n = 7 and k = 3, the array [1,2,3,4,5,6,7] is rotated to [5,6,7,1,2,3,4].
Note:
Try to come up as many solutions as you can, there are at least 3 different ways to solve this problem.
Related problem: Reverse Words in a String II
---------------------------------------------------------------
三步翻转
class Solution {
public:
    void rotateHelper(vector<int>& nums, int start, int end) {
       for (int i = 0; i < (end - start + 1) / 2; i++) {
            int temp = nums[i + start];
            nums[i + start] = nums[end - i];
            nums[end - i] = temp;
        }
    }

    void rotate(vector<int>& nums, int k) {
        k %= nums.size();
        rotateHelper(nums,0,nums.size() - k - 1);
        rotateHelper(nums,nums.size() - k, nums.size() - 1);
        rotateHelper(nums,0,nums.size() - 1);
    }
};

Reverse Bits
Reverse bits of a given 32 bits unsigned integer.
For example, given input 43261596 (represented in binary as 00000010100101000001111010011100), return 964176192 (represented in binary as00111001011110000010100101000000).
Follow up:
If this function is called many times, how would you optimize it?
Related problem: Reverse Integer
----------------------------------
read: http://articles.leetcode.com/2011/08/reverse-bits.html
class Solution {
public:
    uint32_t reverseBits(uint32_t n) {
        uint32_t rt = 0;
        for (int i = 0; i < 32; i++) {
            rt <<= 1;
            if (n & 1) {
                rt += 1;
            }
            n >>= 1;
        }
        
        return rt;
    }
};

Number of 1 Bits
only count ones, not zeros
class Solution {
public:
    int hammingWeight(uint32_t n) {
        int count = 0;
        while (n) {
            n = n & n - 1;
            count++;
        }
        
        return count;
    }
};
House Robber
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.
-------------------------------------------------
DP, dp[i] has the max profit [0 : i] and i is robbed
O(n) space
class Solution {
public:
    int rob(vector<int>& nums) {
        int n = nums.size();
        vector<int> dp(n + 2,0);
        for (int i = n - 1; i >= 0; i--) {
            dp[i] = max(nums[i] + dp[i + 2],dp[i + 1]);
        }
        
        return dp[0];
    }
};

递归:发现重复子问题,所以DP
int rob(vector<int> &houses,int i) {
    if (i == houses.size()) return 0;
    if (i == houses.size() - 1) {
        return houses[i];
    }
    
    return max(houses[i] + rob(houses,i + 2),rob(houses,i + 1));
}

Optimized, O(1) space
class Solution {
public:
    int rob(vector<int>& nums) {
        int n = nums.size();
        int pre1 = 0,pre2 = 0;
        for (int i = n - 1; i >= 0; i--) {
            int cur = max(nums[i] + pre2,pre1);
            pre2 = pre1;
            pre1 = cur;
        }
        
        return pre1;
    }
};

Day 103, ##, Repeated DNA Sequences

All DNA is composed of a series of nucleotides abbreviated as A, C, G, and T, for example: "ACGAATTCCG". When studying DNA, it is sometimes useful to identify repeated sequences within the DNA.
Write a function to find all the 10-letter-long sequences (substrings) that occur more than once in a DNA molecule.
For example,
Given s = "AAAAACCCCCAAAAACCCCCCAAAAAGGGTTT",

Return:
["AAAAACCCCC", "CCCCCAAAAA"].
-----------------------------------------------------
Solution #1, unordered_map would get Memory Limit Exceeded.

class Solution {
public:
    vector<string> findRepeatedDnaSequences(string s) {
        vector<string> rt;
        hash<string> hash_fn;
        if (s.length() < 11) return rt;
        
        unordered_map<int,int> map;
        for (int i = 0; i < s.length() - 9; i++) {
            string sub = s.substr(i,10);
            int hashN = hash_fn(sub);
            
            if (map.find(hashN) == map.end()) {
                map[hashN] = 1;
            }else if (map[hashN] == 1){
                rt.push_back(sub);
                map[hashN]++;
            }
        }

        return rt;
    }
};
Solution #2, convert ACGT to 4-bit representation, so the space cost of one key is reduced from 10 * 8 bits to 2 bits
public:
    vector<string> findRepeatedDnaSequences(string s) {
        vector<string> rt;
        if (s.length() < 11) return rt;
        
        unordered_map<char,int> map;
        map['A'] = 0;
        map['C'] = 1;
        map['G'] = 2;
        map['T'] = 3;
        
        unordered_map<int,int> count;
        unsigned hash = 0;
        for (int i = 0; i < s.length(); i++) {
            hash <<= 2;
            hash += map[s[i]];
            if (i > 8) {
                hash &= (1 << 20) - 1;
                if (count.find(hash) == count.end()) {
                    count[hash] = 1;
                }else if (count[hash] == 1) {
                    count[hash]++;
                    rt.push_back(s.substr(i - 9,10));
                }
            }
        }
        
        return rt;
    }
};
another solution https://leetcode.com/discuss/24478/i-did-it-in-10-lines-of-c