Leetcode0720. 词典中最长的单词(simple)

目录

1. 题目描述

2. 解题分析

2.1 广度优先搜索

2.2 预处理:按单词长度先排序

2.3 哈希表

2.4 字典树

3. 代码实现


1. 题目描述


给出一个字符串数组 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] 都只包含小写字母。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/longest-word-in-dictionary
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

2. 解题分析

        题目并不是要求找最长的单词,而是能够通过一个一个字符添加而构建出的单词中的最长者。所以,对于符合题意得某个长度为k的单词a,在字典中一定存在这样一个单词序列:

a[0]=a[0:1], \ a[0:2],\ ...,\ a[0:k]=a

        所以第一感是从每个长度为1的单词开始搜索,看它通过每次追加一个字符(在字典范围内搜索能匹配的单词)的增长方式,能够增长到的最大长度。

2.1 广度优先搜索

        似乎可以用广度优先搜索的方法来做。只不过不是从固定的某个根节点开始BFS,而是要以所有长度为1的单词为根节点分别进行搜索。基本算法流程如下:

        if k in range(len(words):

                if len(words[k])==1:

                        以words[k]为根节点进行广度优先搜索找到距离根节点距离最远的单词

                        (如果有多个,取其中序号最小的)

                        比较更新最长单词

        但是,这个思路显得有点复杂。广度优先搜索时每次搜索邻节点都几乎是需要遍历字典,而且还可能需要进行多次广度优先搜索。想一想头皮发麻。

2.2 预处理:按单词长度先排序

        根据以上分析,符合条件的单词序列一定是按长度1,2,3....生长出来的。因此可以先对字典按长度进行排序。可以用哈希表来存储整个字典,以长度为键值,其value则是字典中所有长度为该键值的单词的列表。

        基于这个哈希表再应用广度优先搜索算法(主要是遍历邻节点时效果大大提高)应该就容易实现多了,能够大大降低复杂度。这种进行进行结构化预处理也是常用手段。最常见的数据预处理手段莫过于将数组排序成有序数组后再处理了。

2.3 哈希表

        本方法也是将字典按单词长度先排序(这个排序用哈希表存储)。排完序后,按长度升序将可能合法的结果加入到另一个哈希表中。可能合法的单词的判断依据为:

  • 空字符串为合法单词,这个是初始或者边界条件
  • 如果某单词去掉最后一个字母后存在于哈希表中--这个意味着该单词能够由另一个单词通过再尾部增加一个字母而得到,则该单词为合法单词(因为其前面的单词也是以这种方式挑选出来的)

        但是当多个单词长度相同并可以由相同的单词生长而来,题目要求选择其中字典序较小的为答案。可以考虑在最初字典排序时将相同长度的单词按照字典序降序排列。这样,在遍历过程中相同长度的合法单词中最后那个被遍历到的在原字典序中恰为最小的,满足题目要求。

        如何确定字典序的大小呢?python中直接用sorted()函数就可以对字符串进行排序,将reverse参数设为True就时降序排列了。

2.4 字典树

        待补充。

3. 代码实现

        以下代码实现的是2.3解的思路。考虑到第2个哈希表只需要存储键,不需要存储值,所以使用python set()来实现。

import time
from typing import List	

class Solution:
    def longestWord(self, words: List[str]) -> str:
        h1 = dict()
        for k,word in enumerate(words):
            # print(k,word)
            if len(word) in h1:
                h1[len(word)].append(word)
            else:
                h1[len(word)] = [word]
        # print(h1)
        h2 = set()
        key = 1
        ans = ''
        while key in h1:                
            # 相同长度按字典序降序排列
            wlst = sorted(h1[key], reverse=True)
            # print(key,wlst)            
            if key == 1:
                # All words of length 1 are valid word
                for w in wlst:
                    h2.add(w)
                    ans = w
            else:
                for w in wlst:
                    if w[:-1] in h2:
                        h2.add(w)
                        ans = w                        
            key += 1
        return ans            

if __name__ == '__main__':            
    
    sln = Solution()

    words = ["w","wo","wor","worl", "world"]
    tStart = time.time()        
    ans = sln.longestWord(words)
    tElapsed = time.time() - tStart            
    print('ans={0}, tCost={1:3.2f}(sec)'.format(ans,tElapsed))             
    
    words = ["a", "banana", "app", "appl", "ap", "apply", "apple"]
    tStart = time.time()        
    ans = sln.longestWord(words)
    tElapsed = time.time() - tStart            
    print('ans={0}, tCost={1:3.2f}(sec)'.format(ans,tElapsed))              
    
    words = ["m","mo","moc","moch","mocha","l","la","lat","latt","latte","c","ca","cat"]
    tStart = time.time()        
    ans = sln.longestWord(words)
    tElapsed = time.time() - tStart            
    print('ans={0}, tCost={1:3.2f}(sec)'.format(ans,tElapsed)) 

回到主目录:笨牛慢耕的Leetcode解题笔记(动态更新。。。)icon-default.png?t=M276https://chenxiaoyuan.blog.csdn.net/article/details/123040889

你可能感兴趣的:(算法与数据结构,python,算法,数据结构,leetcode,哈希表)