【问题标题】:Represent a word with an alphabet用字母表表示一个词
【发布时间】:2013-08-14 19:48:35
【问题描述】:

这是一道面试题:

Imagine an alphabet of words. Example:
a ==> 1
b ==> 2
c ==> 3
.
z ==> 26
ab ==> 27
ac ==> 28
.
az ==> 51
bc ==> 52
and so on.

这样字符序列只需按升序排列(ab 有效但 ba 无效)。给定任何单词,如果有效则打印其索引,否则打印 0。

Input Output
ab 27
ba 0
aez 441

注意:暴力是不允许的。这是问题的链接:http://www.careercup.com/question?id=21117662

我可以将解决方案理解为:

  • 总字数为 2^26 -1。
  • 对于给定的单词,大小小的单词首先出现。
  • 设 n 为单词的长度,
    • 大小小于 n 的单词总数为 C(26, 1) + C(26, 2) + ...+ C(26, n -1)
  • 然后计算在给定单词之前有多少个大小相同的单词
  • 两个数字加一的和就是结果

参考:sites.google.com/site/spaceofjameschen/annnocements/printtheindexofawordwithlettersinascendingorder--microsoft

在示例解决方案中,我了解了作者如何计算大小小于 word.size() 的单词数。但是,在代码中,我不太确定如何找到与 word.size() 大小相同且出现在 'word' 之前的单词数。

没错,就是这一点:

char desirableStart;  
i = 0;
while( i < str.size()){     
    desirableStart = (i == 0) ? 'a' : str[i - 1] + 1;   

    for(int j = desirableStart; j < str[i]; ++j){
        index += NChooseK('z' - j, str.size() - i - 1);     // Choose str.size() - i - 1 in the available charset
    }

    i ++;
}

有人可以帮我理解这一点吗?谢谢。

【问题讨论】:

  • 在编写任何代码之前,您应该在纸上研究问题。尝试示例,设计和测试算法,并证明正确性。编码是一种干扰。计算机可以帮你计算,但不能帮你思考

标签: algorithm data-structures count


【解决方案1】:

首先(你可能得到了这部分,但为了完整起见),NChooseK 函数计算二项式系数,即从一组 k 个元素中选择的方法数 n 个元素。此函数在您的 cmets 中称为 C(n, k),因此我将使用相同的符号。

由于字母是排序的而不是重复的,这正是创建问题中描述的 n 字母单词的方法的数量,所以这就是为什么函数的第一部分是让您处于正确的位置:

int index = 0;
int i = 1;

while(i < str.size()) {
    // choose *i* letters out of 26
    index += NChooseK(26, i);
    i++;
}

例如,如果您的输入是 aez,这将获得单词 yz 的索引,这是最后一个可能的 2 字母组合:C(26, 1) + C(26, 2) = 351

此时,你有了你的n-字母单词的初始索引,需要看看你需要跳到多少个n-字母单词的组合到达单词的结尾。为此,您必须检查每个单独的字母并计算所有可能的字母组合,从前一个字母之后的一个字母开始(代码中的 desirableStart 变量),并以正在检查的字母结尾。

例如,对于aez,您将执行以下操作:

  1. 获取最后 2 个字母的单词索引 (yz)。
  2. 将索引加一(这实际上是在您的代码末尾完成的,但在这里这样做更有意义以保持正确的位置):现在我们的索引为abc
  3. 首字母为a,无需增加。你还在abc
  4. 第二个字母是e,计算第二个字母的组合从be。这会将您带到aef(请注意,f 是本示例中第一个有效的第三个字符,desirableStart 负责处理)。
  5. 第三个字母是z,计算第三个字母的组合,从fz。这会将您转到aez

这就是你代码的最后一部分的作用:

// get to str.size() initial index (moved this line up)
index ++;

i = 0;
while( i < str.size()) { 

    // if previous letter was `e`, we need to start with `f`
    desirableStart = (i == 0) ? 'a' : str[i - 1] + 1;   

    // add all combinations until you get to the current letter
    for (int j = desirableStart; j < str[i]; ++j) {

        char validLettersRemaining = 'z' - j;
        int numberOfLettersToChoose = str.size() - i - 1;
        index += NChooseK(validLettersRemaining, numberOfLettersToChoose);
    }

    i++;
}

return index;

【讨论】:

  • 时隔3年再次阅读此说明,单次阅读仍能理解。有没有办法可以给这个答案一个“双重喜欢”?! :)
  • @Darth.Vader:非常感谢,很高兴听到。老实说,现在是我国家的早晨,我正在喝我的第一杯咖啡,但我不知道这段代码是什么意思。 :)
  • 当我半睡半醒时写一些代码,第二天早上醒来却想知道:昨晚是谁写的……不是我。
【解决方案2】:

相同大小的单词数的计算与较短单词的计算没有区别。

你可能会被 c 中从 0 开始的数组索引引入歧途。因此尽管i &lt; str.size() 可能会提出其他建议,但此循环的最后一次迭代实际上计算与索引为的单词大小相同的单词计算出来的。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-04-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-09-21
    • 1970-01-01
    相关资源
    最近更新 更多