leetcode--高级数据结构

本文介绍了字典树(Trie树)的基本概念、数据结构及其实现方法,包括插入、查找、前缀查询等功能,并展示了如何利用正则表达式进行单词搜索。此外,还介绍了并查集的概念及其在解决朋友圈圈子问题中的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

基础知识:

Trie树(字典树)

利用字符串的公共前缀来减少储存空间和查询时间。

数据结构:

#define TRIE_MAX_CHAR_NUM 26
struct TrieNode{
    TrieNode *child[TRIE_MAX_CHAR_NUM];
    bool is_end;
    TrieNode() : is_end(false){
        for (int i = 0; i < TRIE_MAX_CHAR_NUM; i++){
            child[i] = 0;
        }
    }
};

获取全部单词:

前序遍历,放进一个栈,前序遍历压入节点,在后序遍历时弹出节点。

void get_all_word_from_trie(TrieNode *node, string &word, vector<string> &word_list){
    for (int i = 0; i < TRIE_MAX_CHAR_NUM; i++){
        if (node->child[i]){
            word.push_back(i + 'a');
            if (node->child[i]->is_end){
                word_list.push_back(word);
            }
            get_all_word_from_trie(node, word, word_list);
            word.erase(word.length()-1, 1);
        }
    }
}

插入

一个循环word遍历树的过程

void insert(const char *word, TrieNode root){
    TrieNode *ptr = &root;
    while(word){
        int pos = *word - 'a';
        if (!ptr->child[pos]){
            ptr->child[pos] = new TrieNode();
        }
        ptr = ptr->child[pos];
        word++;
    }
    ptr->is_end = true;
}

搜索

与插入类似,没找到节点返回false,到word最后字符,返回is_end的值。

bool search(const char *word, TrieNode root){
    TrieNode *ptr = &root;
    while(word){
        int pos = *word - 'a';
        if(!ptr->child[pos]){
            return false;
        }
        ptr = ptr->child[pos];
        word++;
    }
    return ptr->is_end;
}

前缀查询

搜索是否存在前缀,与字符串搜索类似,最后不是返回is_end而是存在就返回true。

bool startsWith(const char *word, TrieNode *root){
    TrieNode *ptr = root;
    while(word){
        int pos = *word - 'a';
        if(!ptr->child[pos]){
            return false;
        }
        ptr = ptr->child[pos];
        word++;
    }
    return true;
}

208. Implement Trie (Prefix Tree)

题意:

实现一个字典树,实现插入、查找、查找前缀的功能。

代码:

#define TRIE_MAX_CHAR_NUM 26

struct TrieNode{
    TrieNode* child[TRIE_MAX_CHAR_NUM];
    bool is_end;
    TrieNode() : is_end(false){
        for (int i = 0; i <= TRIE_MAX_CHAR_NUM; i++){
            child[i] = 0;
        }
    }
};


class Trie {
public:
    /** Initialize your data structure here. */
    Trie() {
    }

    /** Inserts a word into the trie. */
    void insert(string word) {
        TrieNode *ptr = &root;
        for(int i = 0; i < word.length(); i++){
            int pos = word[i] - 'a';
            if (!ptr->child[pos]){
                ptr->child[pos] = new TrieNode();
            }
            ptr = ptr->child[pos];
        }
        ptr->is_end = true;
    }

    /** Returns if the word is in the trie. */
    bool search(string word) {
        TrieNode* ptr = &root;
        for(int i = 0; i < word.length(); i++){
            int pos = word[i] - 'a';
            if (!ptr->child[pos]){
                return false;
            }
            ptr = ptr->child[pos];
        }
        return ptr->is_end;
    }

    /** Returns if there is any word in the trie that starts with the given prefix. */
    bool startsWith(string prefix) {
        TrieNode* ptr = &root;
        for(int i = 0; i < prefix.length(); i++){
            int pos = prefix[i] - 'a';
            if (!ptr->child[pos]){
                return false;
            }
            ptr = ptr->child[pos];
        }
        return true;
    }
private:
    TrieNode root;
};

211. Add and Search Word - Data structure design

题意:

实现一个数据结构,可以以正则表达式的形式搜索单词。就是.可以代表任意的字母。实现数据结构的添加和查找功能。

解题思路:

实现一个tire数,如果遇到字母正常遍历word,遇到.深度优先搜索遍历所有的节点。

代码:

#define TRIE_MAX_CHAR_NUM 26

struct TrieNode{
    TrieNode* child[TRIE_MAX_CHAR_NUM];
    bool is_end = false;
    TrieNode() : is_end(false){
        for (int i = 0; i < TRIE_MAX_CHAR_NUM; i++){
            child[i] = 0;
        }
    }
};

class WordDictionary {
public:
    /** Initialize your data structure here. */
    WordDictionary() {
    }
    ~WordDictionary() {
        for (int i = 0; i < node_vec.size(); i++){
            delete node_vec[i];
        }
    }

    /** Adds a word into the data structure. */
    void addWord(string word) {
        TrieNode *ptr = &root;
        for (int i = 0; i < word.length(); i++){
            int pos = word[i] - 'a';
            if (!ptr->child[pos]){
                ptr->child[pos] = new_node();
            } 
            ptr = ptr->child[pos];
        }
        ptr->is_end = true;
    }

    /** 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) {
        TrieNode *ptr = &root;
        return search_trie(word, ptr, 0);
    }

    bool search_trie(string word,TrieNode* node, int i){
        if (word[i] == '\0'){
            if (node->is_end){
                return true;
            }
            return false;
        }
        if (word[i] == '.'){
            for (int j = 0; j < TRIE_MAX_CHAR_NUM; j++){
                if (node->child[j] && search_trie(word, node->child[j], i+1)){
                    return true;
                }
            }
        }
        else{
            int pos = word[i] - 'a';
            if (node->child[pos] && search_trie(word, node->child[pos], i+1)){
                return true;
            }
        }
        return false;
    }
private:
    TrieNode* new_node(){
        TrieNode* node = new TrieNode();
        node_vec.push_back(node);
        return node;
    }
    TrieNode root;
    vector<TrieNode *> node_vec;
};

并查集:

概念:

通过森林的形式存集合,每个点记录父节点和子节点的个数,父节点等于自己则是根节点,在相同的集合的节点有相同的根节点。

初始化:

class DisjointSet{
public:
    DisjointSet(int n){
        for (int i = 0; i < n; i++){
            _id.push_back(i);
            _size.push_back(1);
        }
        count = n;
    }
private:
    vector<int> _id;
    vector<int> _size;
    int count;
};

路径压缩:

在查询时,隔一个把它连到它的父节点的父节点。
在并操作时,将子节点树少的节点连到子节点数多的根节点,使数尽可能的平衡。

查找操作:

int find(int p){
        while(p != _id[p]){
            _id[p] = _id[_id[p]]; //父节点指向了父节点的父节点
            p = _id[p];
        }
        return p;
    }

并操作:

void union_(int p, int q){
        int i = find(p);
        int j = find(q);
        if (i == j){
            return;
        }
        if (_size[i] > _size[j]){
            _id[j] = i;
            _size[i] += _size[j];
        }
        else{
            _id[i] = j;
            _size[j] += _size[i];
        }
        count--;
    }

547. Friend Circles

解题思路1:

利用并查集,返回集合个数。

代码:

class DisjointSet{
public:
    DisjointSet(int n){
        for (int i = 0; i < n; i++){
            _size.push_back(1);
            _id.push_back(i);
        }
        _count = n;
    }
    int find(int p){
        while (p != _id[p]){
            _id[p] = _id[_id[p]];
            p = _id[p];
        }
        return p;
    }
    void union_(int p, int q){
        int i = find(p);
        int j = find(q);
        if (i == j){
            return;
        }
        if (_size[i] > _size[j]){
            _id[j] = i;
            _size[i] += _size[j]; 
        }
        else{
            _id[i] = j;
            _size[j] += _size[i];
        }
        _count--;
    }
    int count(){
        return _count;
    }
private:
    vector<int> _id;
    vector<int> _size;
    int _count;
};

class Solution {
public:
    int findCircleNum(vector<vector<int>>& M) {
        DisjointSet disjoint_set(M.size());
        for (int i = 0; i < M.size(); i++){
            for (int j = i+1; j < M.size(); j++){
                if (M[i][j]){
                    disjoint_set.union_(i, j);
                }
            }
        }
        return disjoint_set.count();
    }
};

解题思路2:

深度优先搜素的方法:
遍历节点(如果visit数组为0),深度优先搜索该节点,设置一个visit数组,遍历过的节点的visit标记为1,计数需要经过多少次遍历可以遍历完所有的节点。

代码:

class Solution {
public:
    int findCircleNum(vector<vector<int>>& M) {
        vector<int> visit(M.size(), 0);
        int result = 0;
        for (int i = 0; i < visit.size(); i++){
            if (visit[i] == 0){
                DFS(M, visit, i);
                result++;
            }
        }
        return result;
    }

    void DFS(vector<vector<int>>& M, vector<int> &visit, int node){
        visit[node] = 1;
        for (int i = 0; i < M.size(); i++){
            if (M[node][i] == 1 && visit[i] == 0){
                DFS (M, visit, i);
            }
        }
    }
};

线段树

线段树是一个完全二叉树

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值