[LEETCODE]算法进阶自练习13-14 Trie树&分治算法

271 阅读3分钟

[LEETCODE]算法进阶自练习13-14 Trie树&分治算法

13.Trie树

简单
  1. 词典中最长的单词 leetcode 720  暴力解法:
    string longestWord(vector<string>& words) {
        unordered_set<string> set;
        for(string& word:words){
            set.insert(word);
        }

        string ret = "";
        for(string& word : words){
            int wsize = word.size(), rsize = ret.size();
            if(wsize>rsize || (wsize==rsize && word.compare(ret)<0)){
                bool bfind = true;
                for(int i=1; i<wsize; ++i){
                    string t = word.substr(0, i);
                    if(set.count(t)){
                        continue;
                    }
                    else{
                        bfind = false;
                        break;
                    }
                }
                if(bfind) ret = word;
            }
        }
        return ret;
    }

 Trie树解法:

class TrieNode{
public:
    vector<TrieNode*> child;
    TrieNode(){
        child = vector<TrieNode*>(26,nullptr);
    }
};
class Solution {
private:
    TrieNode* root;
    string ret;
    int len;
public:
    Solution(){
        root = new TrieNode();
        ret = "";
        len = 0;
    }
    void add(string word){
        int wsize = word.size(), i=0;
        TrieNode* p = root;
        for(; i<wsize-1; i++){
            if(p->child[word[i] - 'a'] == nullptr) return;
            p = p->child[word[i]-'a'];
        }
        p->child[word[i]-'a'] = new TrieNode();
        if(wsize>len || (wsize==len && word < ret)){
            len = wsize;
            ret = word;
        }
    }
    string longestWord(vector<string>& words) {
        sort(words.begin(),words.end());
        for(string& word:words){
            add(word);
        }
        return ret;
    }
};
中等
  1. 实现Trie(前缀树) leetcode 208
class TrieNode{
    public:
    vector<TrieNode*> child;
    bool isWord;
    TrieNode(){
        isWord = false;
        child = vector<TrieNode*>(26,nullptr);
    }
};
class Trie {
public:
    TrieNode* root;
    Trie() {
        root = new TrieNode();
    }
    void insert(string word) {
        int wsize = word.size();
        TrieNode* p = root;
        for(int i=0; i<wsize; i++){ 
            if(p->child[word[i]-'a'] == nullptr){
                p->child[word[i]-'a'] = new TrieNode();
            }
            p = p->child[word[i] - 'a'];
        }
        p->isWord = true;
    }
    bool search(string word) {
        int wsize = word.size();
        TrieNode* p = root;
        for(int i=0; i<wsize && p; ++i){
            p = p->child[word[i]-'a'];
        }
        return p && p->isWord;
    }
    bool startsWith(string prefix) {
        int psize = prefix.size();
        TrieNode* p = root;
        for(int i=0; i<psize&&p; ++i){
            p = p->child[prefix[i]-'a'];
        }
        return p != nullptr;
    }
};
  1. 添加与搜索单词 - 数据结构设计 leetcode 211
class TrieNode{
    public:
    vector<TrieNode*> child;
    bool isWord;
    TrieNode(){
        isWord = false;
        child = vector<TrieNode*>(26,nullptr);
    }
};
class WordDictionary {
public:
    TrieNode* root;
    WordDictionary() {
        root = new TrieNode();
    }
    
    void addWord(string word) {
        int wsize = word.size();
        TrieNode* p = root;
        for(int i=0; i<wsize&&p; ++i){
            if(p->child[word[i]-'a'] == nullptr){
                p->child[word[i]-'a'] = new TrieNode();
            }
            p = p->child[word[i]-'a'];
        }
        p->isWord = true;
    }
    
    bool subSearch(TrieNode* p, string word){
        if(p == nullptr) return false;
        int wsize = word.size();
        for(int i=0; i<wsize; i++){
            if(word[i] == '.'){
                for(int j=0; j<26; j++){
                    if(subSearch(p->child[j], word.substr(i+1))) return true;
                }
                return false;
            }
            if(p->child[word[i] - 'a'] == nullptr) return false;
            p = p->child[word[i]-'a'];
        }
        return p->isWord;
    }
    bool search(string word) {
        return subSearch(root, word);
    }
};

困难

1.单词搜索II leetcode 212

class TrieNode{
public:
    string word;
    vector<TrieNode*> child;
    TrieNode(){
        word = "";
        child = vector<TrieNode*>(26, nullptr);
    }
};
class Solution {
    int m; // 行
    int n; // 列
    vector<string> ret;
public:
    void checkWord(vector<vector<char>>& board, TrieNode* root, int i, int j){
        char c = board[i][j];
        if(c=='.' || root->child[c-'a'] == nullptr) return;

        root = root->child[c-'a'];
        if(root->word !=  ""){
            ret.emplace_back(root->word);
            root->word = "";
        }
        board[i][j] = '.';
        if(i>0) checkWord(board,root,i-1,j);
        if(j>0) checkWord(board,root,i,j-1);
        if(i+1<m) checkWord(board,root,i+1,j);
        if(j+1<n) checkWord(board,root,i,j+1);
        board[i][j] = c;
    }
    vector<string> findWords(vector<vector<char>>& board, vector<string>& words) {
        m = board.size();
        n = (m == 0 ? 0 : board[0].size());
        if(m ==0 || n == 0) return ret;

        TrieNode* root = new TrieNode();
        for(string& word:words){
            TrieNode* p = root;
            int wsize = word.size();
            for(int i=0; i<wsize; i++){
                if(p->child[word[i]-'a'] == nullptr) p->child[word[i]-'a'] = new TrieNode();
                p = p->child[word[i]-'a'];
            }
            p->word = word;
        }
        for(int i=0; i<m; i++){
            for(int j=0; j<n; j++){
                checkWord(board, root, i, j);
            }
        }
        return ret;
    }
};

14.分治算法

简单
  1. 多数元素 leetcode 169  Boyer-Moore 投票算法:
    int majorityElement(vector<int>& nums) {
        int nsize = nums.size();
        int candinate = -1, count = 0;
        for(int i=0; i<nsize; i++){
            if(candinate == nums[i]){
                count++;
            }
            else{
                count--;
                if(count < 0){
                    candinate = nums[i];
                    count = 1;
                }
            }
        }
        return candinate;
    }

 排序解法:

    int majorityElement(vector<int>& nums) {
        sort(nums.begin(), nums.end());
        return nums[nums.size()/2];
    }

 哈希表解法:

    int majorityElement(vector<int>& nums) {
        map<int, int> mp;
        int nsize = nums.size();
        for(int i=0; i<nsize; i++) mp[nums[i]]++;
        int ret = 0;
        auto it = mp.begin();
        while(it != mp.end()){
            if(it->second > nsize/2){ // 注意这里是大于不包含等于
                ret = it->first;
                break;
            }
            it++;
        }
        return ret;
    }

 分治解法:

    int countInRange(vector<int>& nums, int target, int low, int high){
        int count = 0;
        for(int i=low; i<=high; i++) if(nums[i] == target) count++;
        return count;
    }
    int majorityElementRec(vector<int>& nums, int low, int high){
        if(low == high) return nums[low];
        int mid = low + (high-low)/2;
        int left_m = majorityElementRec(nums, low, mid);
        int right_m = majorityElementRec(nums, mid+1, high);
        if(countInRange(nums, left_m, low, high) > (high - low + 1)/2) return left_m;
        if(countInRange(nums, right_m, low, high) > (high -low + 1)/2) return right_m;
        return -1;
    }
    int majorityElement(vector<int>& nums) {
        return majorityElementRec(nums,0,nums.size()-1);
    }
中等
  1. 最大子序和 leetcode 53  暴力解法:
    int maxSubArray(vector<int>& nums) {
        int nsize = nums.size(), max_n = INT_MIN;;
        for(int i=0; i<nsize; i++){
            int t_sum = 0;
            for(int j=i; j<nsize; j++){
                t_sum += nums[j];
                max_n = max(t_sum,max_n);
            }
            
        }
        return max_n;
    }

 动态规划解法:

    int maxSubArray(vector<int>& nums) {
        int nsize = nums.size(), pre = 0, ret = nums[0];
        for(int i=0; i<nsize; i++){
            pre = max(nums[i], pre + nums[i]);
            ret = max(ret,pre);
        }
        return ret;
    }

 贪心解法:

    int maxSubArray(vector<int>& nums) {
        int nsize = nums.size(), sum = 0, ret = INT_MIN;
        for(int i=0; i<nsize; i++){
            sum += nums[i];
            ret = max(ret,sum);
            if(sum < 0) sum = 0;
        }
        return ret;
    }

 分治解法:

    int maxSubArrayRange(vector<int>& nums, int left, int right){
        if(left == right) return nums[left];
        int mid = left + (right - left)/2;
        int left_s = maxSubArrayRange(nums,left,mid);
        int right_s = maxSubArrayRange(nums,mid+1,right);
        int mid_s = maxSubArrayCrossRange(nums,left,mid,right);
        return max(max(left_s, right_s),mid_s);   
    }
    int maxSubArrayCrossRange(vector<int>& nums, int left, int mid, int right){
        int left_s = INT_MIN, sum = 0;
        for(int i=mid; i>=left; i--){
            sum +=nums[i];
            left_s = max(left_s,sum);
        }
        int right_s = INT_MIN; sum = 0;
        for(int i=mid+1; i<=right; i++){
            sum += nums[i];
            right_s = max(right_s, sum);
        }
        return left_s + right_s;
    }
    int maxSubArray(vector<int>& nums) {
        int nsize = nums.size();
        int ret = maxSubArrayRange(nums,0,nsize-1);
        return ret;
    }
  1. 搜索二维矩阵 leetcode 240  二分法:
    bool binarySearch(vector<vector<int>>& matrix, int target, int i, bool isV){
        int l = i, h = isV ? matrix[0].size()-1 : matrix.size()-1;
        while(l<=h){
            int m = l + (h-l)/2;
            if(isV){ // 垂直搜索
                if(matrix[i][m] == target) return true;
                if(matrix[i][m] < target){
                    l = m+1;
                }
                else{
                    h = m-1;
                }
            }
            else{ // 水平搜索 搜索行
                if(matrix[m][i] == target) return true;
                if(matrix[m][i] < target){
                    l = m+1;
                }
                else{
                    h = m-1;
                }
            }
        }
        return false;
    }
    bool searchMatrix(vector<vector<int>>& matrix, int target) {
        if(matrix.size() == 0 || matrix[0].size() == 0) return false;

        int shortdim = min(matrix.size(),matrix[0].size());
        for(int i=0; i<shortdim; i++){
            bool vFind = binarySearch(matrix, target, i, true);
            bool hFind = binarySearch(matrix, target, i, false);
            if(vFind || hFind) return true;
        }
        return false;
    }

 缩减搜索空间:

    bool searchRec(vector<vector<int>>& matrix, int left, int right, int up, int down, int target){
        if(left > right || up > down) return false;
        if(matrix[up][left] > target || matrix[down][right] < target){
            return false;
        }
        int mid = left + (right - left)/2;
        int row = up;
        while(row <= down && matrix[row][mid] <= target){
            if(matrix[row][mid] == target) return true;
            row++;
        }
        return searchRec(matrix, left, mid-1, row, down, target) || searchRec(matrix, mid+1, right, up, row-1, target);
    }
    bool searchMatrix(vector<vector<int>>& matrix, int target) {
        if(matrix.size() == 0 || matrix[0].size() == 0) return false;
        return searchRec(matrix, 0, matrix[0].size()-1, 0, matrix.size()-1, target);
    }

 左下角开始遍历解法:

    bool searchMatrix(vector<vector<int>>& matrix, int target) {
        int m = matrix.size();
        int n = (m==0?0:matrix[0].size());
        int i = m-1, j = 0;
        while(i>=0 && j < matrix[0].size()){
            if(matrix[i][j] == target) return true;
            matrix[i][j] > target ? i-- : j++;
        }
        return false;
    }