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;
    }
};

No comments:

Post a Comment