【问题标题】:Shortest word in a dictionary containing all letters包含所有字母的字典中最短的单词
【发布时间】:2015-02-06 22:23:01
【问题描述】:

我在一次采访中被问到这个问题。

给定一个字符数组,在包含所有字符的字典中找到最短的单词。另外,提出一个字典的实现来优化这个函数调用。

例如字符 [] 字符 = { 'R' , 'C' }。结果应该是单词“CAR”。

我想不出任何可以合理快速运行的东西。我想通过构建一个哈希表来预处理字典以检索特定长度的所有单词。然后我只能考虑按长度递增的顺序检索所有单词并检查其中任何一个是否存在所需的字符(可能通过使用位掩码。)

【问题讨论】:

  • 其实第一个结果应该是Cr,Chromium的缩写:D

标签: algorithm


【解决方案1】:

这是一个常见的软件面试问题,其解决方案是:按长度对字典本身进行排序,并按字母顺序对每个值进行排序。给定字符后,对它们进行排序并找到所需的字母。

【讨论】:

    【解决方案2】:

    首先按长度升序对字典进行排序。

    对于每个字母,构建包含该字母的单词在字典中的位置的位图。每个位图都会很长,但不会很多。

    对于每次搜索,取数组中字母的位图交集。结果中的第一个位将位于对应于字典中包含所有字母的最短单词的位置的索引处。

    【讨论】:

      【解决方案3】:

      其他答案更好,但我意识到这是完全可以预先计算的。

      • 对于每个单词
        • 对字母进行排序并删除重复项
        • 字母序列可以看成一个位掩码,A=0bit, B=1bit...Z=26bit。根据该单词中的字母设置掩码A的位。
        • 对于掩码 A 中的每个设置位组合,制作一个子集掩码 B
          • 如果已经有一个词与这个掩码 B 相关联
            • 而且这个词更短,用这个替换相关的词
            • 否则尝试下一个 B
          • 如果没有与掩码 B 关联的单词
            • 将此词与掩码 B 相关联。

      这将花费大量的设置时间,随后的关联存储将在 1.7GB 附近,但您可以在 O(1) 时间内找到包含字母超集的最短单词保证。

      【讨论】:

        【解决方案4】:

        显而易见的预处理是按照长度和字母顺序对字典中的所有单词进行排序:例如,“dorw”下的“word”。然后您可以使用通用搜索算法(例如,正则表达式)来搜索您需要的字母。在最坏的情况下,高效的 (DFA) 搜索只需要遍历字典一次,如果第一次匹配很短,则更少。

        【讨论】:

          【解决方案5】:

          这是 C# 中的一个解决方案:

          using System.Collections.Generic;
          using System.Linq;
          
          public class ShortestWordFinder
          {
              public ShortestWordFinder(IEnumerable<string> dictionary)
              {
                  this.dictionary = dictionary;
              }
          
              public string ShortestWordContaining(IEnumerable<char> chars)
              {
                  var wordsContaining = dictionary.Where(s =>
                  {
                      foreach (var c in chars)
                      {
                          if (!s.Contains(c))
                          {
                              return false;
                          }
          
                          s = s.Remove(s.IndexOf(c), 1);
                      }
          
                      return true;
                  }).ToList();
          
                  if (!wordsContaining.Any())
                  {
                      return null;
                  }
          
                  var minLength = wordsContaining.Min(word => word.Length);
                  return wordsContaining.First(word => word.Length == minLength);
              }
          
              private readonly IEnumerable<string> dictionary;
          }
          

          简单测试:

          using System.Diagnostics;
          using Xunit;
          
          public class ShortestWordFinderTests
          {
              [Fact]
              public void Works()
              {
                  var words = new[] { "dog", "moose", "gargoyle" };
                  var finder = new ShortestWordFinder(words);
                  Trace.WriteLine(finder.ShortestWordContaining("o"));
                  Trace.WriteLine(finder.ShortestWordContaining("oo"));
                  Trace.WriteLine(finder.ShortestWordContaining("oy"));
                  Trace.WriteLine(finder.ShortestWordContaining("eyg"));
                  Trace.WriteLine(finder.ShortestWordContaining("go"));
                  Assert.Null(finder.ShortestWordContaining("ooo"));
              }
          }
          

          【讨论】:

            【解决方案6】:

            预处理

            一个。将单词排序为字母字符数组。保留从排序到原始单词的映射

            b.按照您的建议按字长拆分字典

            c。按字母顺序对每个字长设置的条目进行排序

            函数调用

            1. 按字母顺序对字符数组进行排序
            2. 从与数组长度相同的组开始
            3. 遍历条目测试字符,直到条目的第一个字母按字典顺序大于 char 数组中的第一个字母,然后中断。如果匹配则返回原始单词(参见上面的映射)
            4. 返回 2 获取下一个最长的词组

            有趣的扩展。多个单词可能映射到 a 中的同一个条目。你应该返回哪一个......

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 2021-04-16
              • 1970-01-01
              • 2014-10-27
              • 1970-01-01
              • 2021-08-10
              • 2015-06-28
              • 2018-09-13
              相关资源
              最近更新 更多