leetcode:720. 词典中最长的单词

题目来源

题目描述

在这里插入图片描述

题目解析

set

  • 对数组排序,再利用Set对字母存储,小的单词一定包含在后面大的单词里面。后面只需要取前缀相同的
  • 对字母排序后,第一个单词一定是共有的,后面只需在此基础上添加
class Solution {
public:
    string longestWord(vector<string>& words) {
        //1、先排序
        std::sort(words.begin(), words.end());

        //2、建立set
        std::string ans;
        std::set<std::string> set;
        for(auto &word : words){
            //提取当前字符串的前n-1个字符,如果在set中找得到。也就是去除最后一个字符,发现其子串在之前出现过,说明当前字符是由前面的串插入一个字符合成的
            if(word.length() == 1 ||set.count(word.substr(0, word.size() - 1))){
                set.insert(word);
                ans = word.size() > ans.size() ? word : ans;
            }
        }
        return ans;
    }
};

在这里插入图片描述

字典树

Trie,又称前缀树或字典树,是一棵有根树,其每个节点包含如下字段:

  • 指向子节点的指针数组children。就本题而言,数组长度为26,即小写英文字母的数量。此时 c h i l d r e n [ 0 ] children[0] children[0] 对应小写字母 a, c h i l d r e n [ 1 ] children[1] children[1] 对应小写字母 b,…, c h i l d r e n [ 25 ] children[25] children[25] 对应小写字母 z。
  • 布尔字段isEnd,表示该节点是否为字符串的结尾
    在这里插入图片描述

插入字符串

我们从字典树的根开始,插入字符串。对于当前字符对应的子节点,有两种情况:

  • 子节点存在。沿着指针移动到子节点,继续处理下一个字符
  • 子节点不存在。创建一个新的子节点,记录在children数组的对应位置上,然后沿着指针移动到子节点,继续搜索下一个字符。

重复以上步骤,直到处理字符串的最后一个字符,然后将当前节点标记为字符串的结尾。

查找前缀

我们从字典树的根开始,查找前缀。对于当前字符对应的子节点,有两种情况:

  • 子节点存在。沿着指针移动到子节点,继续搜索下一个字符。
  • 子节点不存在。说明字典树中不包含该前缀,返回空指针。

重复以上步骤,直到返回空指针或搜索完前缀的最后一个字符。

若搜索到了前缀的末尾,就说明字典树中存在该前缀。此外,若前缀末尾对应节点的isEnd 为真,则说明字典树中存在该字符串。

思路

由于符合要求的单词的每个前缀都是符合要求的单词,因此可以使用字典树存储所有符合要求的单词。

  • 创建字典树,遍历数组words并将每个单词插入字典树。
  • 当所有的单词都插入字典树之后,将答案初始化为空字符串,再次遍历数组words,判断每个单词是否是符合要求的单词,更更新答案。
  • 如果一个单词是符合要求的单词,则比较curr_word与ans_word,如果curr_word.size() > ans_word.size(),或者curr_word.size() == ans_word.size()且curr_word的字典序 < ans_word的字典序,则将答案更新为curr_word。
#include <iterator>
#include <deque>
#include <algorithm>
#include <iostream>
#include <functional>
#include <set>
using namespace std;

class Trie{
public:
    Trie(){
        this->children = std::vector<Trie *>(26, nullptr);
        this->isEnd = false;
    }

    bool insert(const std::string &word){
        Trie *node = this;
        for(const auto & ch : word){
            int idx = ch - 'a';
            if(node->children[idx] == nullptr){
                node->children[idx] = new Trie();
            }
            node = node->children[idx];
        }
        node->isEnd = true;
    }

    bool search(const std::string &word){
        Trie *node = this;
        for (const auto & ch : word) {
            int idx = ch - 'a';
            if(node->children[idx] == nullptr  || node->children[idx]->isEnd == false){
                return false;
            }
            node = node->children[idx];
        }
        return node != nullptr && node->isEnd;
    }


private:
    std::vector<Trie *> children;
    bool isEnd;
};

class Solution {
public:
    string longestWord(vector<string>& words) {
       Trie trie;
        for (const auto  & word : words) {
            trie.insert(word);
        }

        std::string longest ;
        for (const auto  & word : words) {
            if(trie.search(word)){
                if (word.size() > longest.size() || (word.size() == longest.size() && word < longest)) {
                    longest = word;
                }
            }
        }
        return longest;
    }
};
int main(){
    Solution a;
    std::vector<std::string> vec {"a", "banana", "app", "appl", "ap", "apply", "apple"};
    std::cout << a.longestWord(vec);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值