力扣每日一题720:词典中最长的单词

文章讲述了如何通过构建字典树和使用哈希集合的方法,在给定一组单词列表中找到由其他单词逐步添加一个字母组成的最长单词,同时保证字典序最小。
摘要由CSDN通过智能技术生成

题目:

难度:中等

提示

给出一个字符串数组 words 组成的一本英语词典。返回 words 中最长的一个单词,该单词是由 words 词典中其他单词逐步添加一个字母组成。

若其中有多个可行的答案,则返回答案中字典序最小的单词。若无答案,则返回空字符串。

示例 1:

输入:words = ["w","wo","wor","worl", "world"]
输出:"world"
解释: 单词"world"可由"w", "wo", "wor", 和 "worl"逐步添加一个字母组成。

示例 2:

输入:words = ["a", "banana", "app", "appl", "ap", "apply", "apple"]
输出:"apple"
解释:"apply" 和 "apple" 都能由词典中的单词组成。但是 "apple" 的字典序小于 "apply" 

提示:

  • 1 <= words.length <= 1000
  • 1 <= words[i].length <= 30
  • 所有输入的字符串 words[i] 都只包含小写字母。

面试中遇到过这道题?

1/5

通过次数

69.3K

提交次数

133.1K

通过率

52.1%

方法一:字典树

看到词典和逐步添加第一想到的就是字典树。先构建好一颗词典树,其中每一个节点的子节点用哈希表来表示。

首先创建一个空的根节点,然后将words中的单词都插入到字典树中,这样就建好了一颗字典树。随后查找最长单词用递归的方法,从根节点开始,动态维护一个递归过程中路径上的单词。当遍历到某个节点cur时,如果cur的某个孩子的end标志位是true,就代表还可以在这个孩子节点上逐步扩增单词,就递归调用这个孩子节点,路径上的单词也对应加一。路径上结果的最长的单词就是答案。

代码

class Solution {
public:
    string ans="";
    struct Node{
        bool end=false;
        char letter;
        //有多个可行答案时,取字典序小的单词,所以不能用unordered_map
        map<char,Node*> next;
        Node(){};
        Node(char c): letter(c) {};
    };
    void insert(string word,Node* root){
        Node* cur=root;
        int n=word.length();
        int i=0;
        //bool falg=true;//标志是否由词典中的单词逐步添加一个字母组成
        while( i<n&&(cur->next).find(word[i])!=(cur->next).end() ){
            cur=(cur->next)[word[i]];
            //if(cur->end==false) flag=false;
            i++;
        }
        if(i==n){
            if(cur->end==false){
                cur->end=true;
            }else{
                return;
            }
        }else{
            while(i<n){
                (cur->next)[word[i]]=new Node(word[i]);
                cur=(cur->next)[word[i]];
                i++;
            }
            cur->end=true;
        }
    }
    string longer(string a,string b){
        if(a.length()>b.length()) return a;
        else if(a.length()<b.length()) return b;
        else if(a<b) return a;
        else return b;
    }
    void dfs(Node* cur,string temp){
        for(auto x:cur->next){
            Node* near=x.second;
            if(near->end==true){
                ans=longer(ans,temp+near->letter);
                dfs(near,temp+near->letter);
            }
        }
    }
    string longestWord(vector<string>& words) {
        Node* root=new Node();
        for(auto word:words){
            insert(word,root);
        }
        string temp="";
        dfs(root,temp);
        return ans;
    }
};

方法二:哈希集合

写完字典树后看答案还有这种方法。

将字典words按照(长度非递减&&字典序递减)排序后,依次遍历for(auto word:words);

如果word是由 words 词典中其他单词逐步添加一个字母组成。那么word(0,word.size()-1)要么是空字符要么存在words中,而我们先前已经排序过,所以word(0,word.size()-1)要么是空字符要么存在words中并且排在word前面。所以我们只需要设置一个字符串集合,集合初始只有一个元素空字符串""。再遍历words是,如果word(0,word.size()-1)能在集合中找到,就将word加入集合,答案更新为word.

下面是官方题解代码

class Solution {
public:
    string longestWord(vector<string> &words) {
        sort(words.begin(), words.end(), [](const string &a, const string &b) {
            return a.size() != b.size() ? a.size() < b.size() : a > b;
        });
        string longest;
        unordered_set<string> candidates = {""};
        for (const auto &word: words) {
            cout<<word<<endl;
            if (candidates.count(word.substr(0, word.size() - 1))) {
                candidates.emplace(word);
                longest = word;
            }
        }
        return longest;
    }
};

  • 5
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值