中级编程通关练习题 #4 – 字符串排列寻址

给定一个全部是大写字母的字符串,计算在该字符串的所有字母所组成的全部排列序列中,当前字符串按照字母顺序所处的位置。譬如:字符串 CODE 四个字母总共可能的排列总数为 4!= 24,按照字母顺序来计算,CODE位于第五位,在CODE之前的四个排列分别是:CDEO,CDOE,CEDO 和 CEOD。

最简单的计算方法是使用函数 permutations来把当前字符串所有可能的排列都找出来,然后寻址就可以得到结果,下面是代码样例:

上面这个方法的缺陷是效率低下,如果字符串的长度超过15个就会非常耗时,如果长度达到25个基本上电脑就要宕机。主要原因是函数permutations在搜索大量排列的场景下极其耗时,字符串长度增加一个,相对应的运算时间呈指数级增长。

所以我们需要采用其他方法来为字符串的排列寻址,要求是字符串长度在25位以内时,寻址的时间不能超过0.5秒。

输入样例:

word = ‘CODEGURUACADEMY’

输出样例:

9066420841

算法思路:

  • 方法一:循环字符串正推 – 上面的输入样例字符串分拆然后按照字母排序后的列表是:[‘A’, ‘A’, ‘C’, ‘C’, ‘D’, ‘D’, ‘E’, ‘E’, ‘G’, ‘M’, ‘O’, ‘R’, ‘U’, ‘U’, ‘Y’],循环word里的每一个字母,分别和这个标准排序列表进行对比,如果字母位置有差异就计算该差异产生的排列数量,从第一个字母逐一计算直到最后一个,然后就可以得到当前字符串在全部排列序列中所处的位置。
  • 方法二:循环字符串倒推 – 先计算出当前字符串所有排列的总数 – 15个字母其中有四对重复字母的排列数量是:15!/ (2! * 2!* 2! * 2!)= 81729648000。然后循环当前字符串的每一个字母,遍历每一个字母时,需要循环所有排列在它前面字母所能产生的排列总数,计算方法是把当前字符串长度乘以当前字母重复数量作为分母,分子就是前面计算出来的全部排列总数。计算完一个字母后,需要从字符串中把该字母删去,然后检查下一个字母,直到字符串为空。