4-14 字典树 并查集 贪心算法

138

贪心算法:

回溯算法:

动态规划:

分治算法:

线段树:

滑动窗口:

队列:

堆栈:

链表:

字典树 :

676. 实现一个魔法字典 211. 添加与搜索单词 - 数据结构设计

class WordDictionary
{
public:
  struct Node
  {
    Node* son[26];
    bool is_end;
    Node() {
      is_end = false;
      for (int i = 0; i < 26 ; i++)
      {
        son[i] = nullptr;
      }
    }
  } *root;
  WordDictionary() {
    root = new Node();
  };
  void addWord(string word) {
    auto p = root;
    for (auto c : word)
    {
        int u = c - 'a';
        if (!p->son[u]) {
            p->son[u] = new Node();
        }
        p = p->son[u];
    }
    p->is_end = true;
  }

  bool find_word(Node* croot, string& word, int si) {
    if (si == word.size()) return croot->is_end;
    
    if (word[si] == '.') {
      // 从root头开始遍历,一一匹配
      for (int i = 0; i < 26; i++)
      {
        if (croot->son[i] && find_word(croot->son[i], word, si + 1)) {
          return true;
        }
      }
    } else {
        int u = word[si] - 'a';
        if (croot->son[u]) {
            return find_word(croot->son[u], word, si + 1);
        } else {
            return false;
        }
    }
    return false;
  }

  bool search(string word) {
    return find_word(root, word, 0);
  }
};

208. 实现 Trie (前缀树)

class Trie {
private:
    bool isEnd;
    vector<Trie*> children;
    Trie* searchWord(string word) {
        Trie* node = this;
        for(char w : word) {
            w -= 'a';
            if (node->children[w] == nullptr) {
                return nullptr;
            }

            node = node->children[w];
        }
        return node;
    }
public:
    /** Initialize your data structure here. */
    
     Trie() : children(26), isEnd(false) {}
    
    /** Inserts a word into the trie. */
    void insert(string word) {
        Trie* node = this;
        for(char w : word) {
            w -= 'a';
            if (node->children[w] == nullptr) {
                node->children[w] = new Trie();
            }
            node = node->children[w];
            
        }
        node->isEnd = true;
    }
    
    /** Returns if the word is in the trie. */
    bool search(string word) {
        Trie* node = this->searchWord(word);
        return node != nullptr && node->isEnd;
    }
    
    /** Returns if there is any word in the trie that starts with the given prefix. */
    bool startsWith(string prefix) {
        return this->searchWord(prefix) != nullptr;
    }
};

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

642. 设计搜索自动补全系统

692. 前K个高频单词

map + sort + sub

212. 单词搜索 II

class Solution(object):
    def findWords(self, board, words):
        """
        :type board: List[List[str]]
        :type words: List[str]
        :rtype: List[str]
        """
        trie = {}
        WORD_KEY = '$'

        # 更新node
        for word in words :
            node = trie

            for letter in word :
                node = node.setdefault(letter, {})
            
            node[WORD_KEY] = word
        

        rowNum = len(board)
        colNum = len(board[0])
        matchedWord = []
        def trackWord(row, col, parent) :
            letter = board[row][col]
            currNode = parent[letter]
            word_match = currNode.pop(WORD_KEY, False)
            if word_match :
                matchedWord.append(word_match)
            
            board[row][col] = '#'
            for (dirRow, dirCol) in [(-1, 0), (0, 1), (1, 0), (0, -1)] :
                newRow = row + dirRow
                newCol = col + dirCol
                if newRow < 0 or newRow >= rowNum or newCol < 0 or newCol >= colNum:
                    continue
                if not board[newRow][newCol] in currNode:
                    continue
                
                trackWord(newRow, newCol, currNode)
            board[row][col] = letter
            if not currNode:
                parent.pop(letter)
            

        
        
        for row in range(rowNum) :
            for col in range(colNum) :
                if board[row][col] in trie :
                    trackWord(row, col, trie)
                
            
        
        return matchedWord

并查集:

128. 最长连续序列 给定一个未排序的整数数组 nums ,找出数字连续的最长序列(不要求序列元素在原数组中连续)的长度。

时间复杂度为 O(n)

输入:nums = [0,3,7,2,5,8,4,6,0,1]

输出:9

class Solution {
public:
    int longestConsecutive(vector<int>& nums) {
        unordered_set<int> myset;
        // 使用set
        for(const int& s: nums) {
            myset.insert(s);
        }
        int maxlen = 0;
        for (int i = 0; i < nums.size(); ++i) {
            // 从头开始
            if (!myset.count(nums[i] - 1)) {
                int len = 1;
                int j = i;
                // 遍历后续+1节点
                while(myset.count(nums[j] + 1)) {
                    len += 1;
                    j++;
                }
                maxlen = max(maxlen, len);
            }
           
        }
        return maxlen;
    }
};

778. 水位上升的泳池中游泳

private class UnionFind {

        private int[] parent;

        public UnionFind(int n) {
            this.parent = new int[n];
            for (int i = 0; i < n; i++) {
                parent[i] = i;
            }
        }
        //找根
        public int root(int x) {
            while (x != parent[x]) {
                //parent[x]往下遍历
                parent[x] = parent[parent[x]];
                x = parent[x];
            }
            return x;
        }
        //根是否同一个
        public boolean isConnected(int x, int y) {
            return root(x) == root(y);
        }

        public void union(int p, int q) {
            if (isConnected(p, q)) {
                return;
            }
            //合并俩节点的根
            parent[root(p)] = root(q);
        }
    }

public class Solution {

    private int N;

    public static final int[][] DIRECTIONS = {{0, 1}, {0, -1}, {1, 0}, {-1, 0}};

    public int swimInWater(int[][] grid) {
        this.N = grid.length;

        int len = N * N;
        // 下标:方格的高度,值:对应在方格中的坐标
        int[] index = new int[len];
        for (int i = 0; i < N; i++) {
            for (int j = 0; j < N; j++) {
                index[grid[i][j]] = getIndex(i, j);
            }
        }

        UnionFind unionFind = new UnionFind(len);
        for (int i = 0; i < len; i++) {
            int x = index[i] / N;
            int y = index[i] % N;

            for (int[] direction : DIRECTIONS) {
                int newX = x + direction[0];
                int newY = y + direction[1];
                if (inArea(newX, newY) && grid[newX][newY] <= i) {
                    unionFind.union(index[i], getIndex(newX, newY));
                }

                if (unionFind.isConnected(0, len - 1)) {
                    return i;
                }
            }
        }
        return -1;
    }

    private int getIndex(int x, int y) {
        return x * N + y;
    }

    private boolean inArea(int x, int y) {
        return x >= 0 && x < N && y >= 0 && y < N;
    }

    private class UnionFind {

        private int[] parent;

        public UnionFind(int n) {
            this.parent = new int[n];
            for (int i = 0; i < n; i++) {
                parent[i] = i;
            }
        }

        public int root(int x) {
            while (x != parent[x]) {
                parent[x] = parent[parent[x]];
                x = parent[x];
            }
            return x;
        }

        public boolean isConnected(int x, int y) {
            return root(x) == root(y);
        }

        public void union(int p, int q) {
            if (isConnected(p, q)) {
                return;
            }
            parent[root(p)] = root(q);
        }
    }
}


class Test {
  constructor(node) {
    for() {
      this.parent[i] = i;
    }
  }
  toUnion(x, y) {
    if (isConnected(x, y)) return
    this.parent[getRoot(x)] = getRoot(y)
  }
  isConnected(x, y) {
    return getRoot(x) == getRoot(y)
  }
  getRoot(x) {
    while(x != this.parent[x]) {
      this.parent[x] = this.parent[this.parent[x]];
      x = this.parent[x];
    }
    return x;
  }

}

const t = new Test("aa")

right = N*N - 1
while(left < right) {
  mid = (left + right) >> 2
  visited = [][]
  if (grid[][] <= mid && dfs(grid, 0, 0, visited, mid)) {
    right = mid
  } else {
    left = mid
  }
}

return left

dfs() {
  visited[][] = true
  for(dir in {{1, 0}, {-1, 0}, {0, 1}, {0, -1}}) {
      if (inArea() && !visited[grid[newx][newy]] && grid[newx][newy] <= threshold) {
          if (== N - 1) return true
          return dfs(grid, newx, newy, visited, threshold)
      }
  }
  return false
}

bfs() {
    queue = [][]
    queue.offer({0, 0})
    boolean[][] visited = new boolean[N][N];
    visited[0][0] = true
    while(!queue.empty()) {
        node = queue.poll
        x = node[0], y = node[1]
        for(dir in {}) {
            newx = x + dir, newy = y + dir
            if (inarea() && !visited && bfs()) {
                if (== N - 1) return true
                queue.offer([newx, newy])
                visited[][] = true
            }
        }
    }
    return false
}


Queue<int> miniHeap = new PriorityQueue<>(Comparator.comparingInt(o->grid[o[0]][o[1]]))
int distto = new Int[n][n]
for(row in disto) {
    Arrays.fill(row, n*n)
}
for() {
    pqueue.push({0, 0})
    while(!pqueue.empty) {
        node = pqueue.poll()
        x = node[0]
        y = node[1]
        for (dir in dirs) {
            newx = dir[0] + x;
            newy = dir[1] + y;
            if (inarea(newx, newy) && !visited && max(distto(), gird()) < distto[newx][newy]) {
                distto[newx][newy] = max(distto(), gird())
            }
            visited[][] = true
            pqueue.offer({newx, newy})
        }
    }
    return -1
}