按字典顺序生成所有的排列

  因为最近在做[url=http://eastsun.iteye.com/category/34059]Project Euler[/url]上的题,里面涉及到的都是和数学有关问题,有一些数学概念会反复出现。比如判断一个数是否为素数,求一些元素的全排列之类。为了方便起见,我把一些功能写成函数,以便以后重复使用。这个帖子介绍的是将一些元素所有的全排列按[url=http://en.wikipedia.org/wiki/Lexicographical_order]字典顺序[/url]依次生成的函数。

[b][size=medium][color=red]☆[/color] Scala代码[/size][/b]
/**
&#Util.scala
utils for mathematical algorithm,include:
# generate all permutations in lexicographical order

@author Eastsun
*/
package eastsun.math

object Util {
/**
Rearranges the elements in the Array[T] src into the lexicographically next smaller permutation of elements.
The comparisons of individual elements are performed using operators <= and >= in Ordered[T]
@return true if the function rearranged the array as a lexicographicaly smaller permutation.
*/
def prevPermutation[T](src:Array[T])
(implicit view:(T) => Ordered[T]):Boolean = {
var i = src.length - 2
while(i >= 0 && src(i) <= src(i+1)) i -= 1
if(i < 0) return false
var j = src.length - 1
while(src(j) >= src(i)) j -= 1
adjustArray(src,i,j)
true
}

/**
Rearranges the elements in the Array[T] src into the lexicographically next greater permutation of elements.
The comparisons of individual elements are performed using operators <= and >= Ordered[T]
@return true if the function rearrange the array as a lexicographicaly greater permutation.
*/
def nextPermutation[T](src:Array[T])
(implicit view:(T) => Ordered[T]):Boolean = {
var i = src.length - 2
while(i >= 0 && src(i) >= src(i+1)) i -= 1
if(i < 0) return false
var j = src.length - 1
while(src(j) <= src(i)) j -= 1
adjustArray(src,i,j)
true
}

private def adjustArray[T](src:Array[T],i:Int,j:Int){
var tmp = src(i)
src(i) = src(j)
src(j) = tmp
var len = (src.length - i)/2
for(k <- 1 to len){
tmp = src(src.length - k)
src(src.length - k) = src(i + k)
src(i + k) = tmp
}
}
}

  算法没什么特别的,如果不清楚google一下即可,这儿就简单说明一下代码。Util中含两个public方法:
def prevPermutation[T](src:Array[T])(implicit view:(T) => Ordered[T]):Boolean
def nextPermutation[T](src:Array[T])(implicit view:(T) => Ordered[T]):Boolean

  顾名思义,第一个[color=orange]prevPermutation[/color]方法是将数组src重排成比当前字典顺序小的上一个排列。注意该方法的返回值为Boolean:如果存在比当前字典顺序小的排列,则重排src,并返回true;否则不影响src并返回false。还算有两点需要注意的地方:
  1.该方法第二个参数view是implicit的,所以调用该方法的时候可以省略。只需要保证类型T有一个到Ordered[T]类型的隐式转换就可以了。
  2.该方法第一个参数src中允许有重复的元素。
   [color=olive]比如对于1,2,3,3,其所有排列按字典顺序排列为:
    1233
    1323
    1332
    2133
    2313
    2331
    3123
    3132
    3213
    3231
    3312
    3321[/color]

[b][size=medium][color=red]☆[/color] 应用[/size][/b]
  下面就通过解决[url=http://eastsun.iteye.com/category/34059]Project Euler[/url]中的两个题来示范一下如何使用这两个API。

[url=http://projecteuler.net/index.php?section=problems&id=24]题目24[/url]:What is the millionth lexicographic permutation of the digits 0, 1, 2, 3, 4, 5, 6, 7, 8 and 9?
[color=darkred]题目简介[/color]:将数字0, 1, 2, 3, 4, 5, 6, 7, 8 ,9的所有排列按字典顺序排序,求排在第1,000,000位的那个数字。(注意:从第一位记起)
  当然这个题有更高效的解决方法,可以参看[url=http://eastsun.iteye.com/blog/204837]Euler Project解题汇总 023 ~ 030[/url]。这里就使用nextPermutation方法暴力解决:
import eastsun.math.Util._

object Euler024 extends Application {
var src = Array(0,1,2,3,4,5,6,7,8,9)
for(idx <- 1 until 1000000) nextPermutation(src)
println(src.mkString(""))
}


[url=http://projecteuler.net/index.php?section=problems&id=41]问题41[/url]:What is the largest n-digit pandigital prime that exists?
[color=darkred]题目简介[/color]:一个数称为pandigital,如果它是数字1,2,……,n的一个排列。比如2143就是一个4位的pandigital。
  现在求所有pandigital中最大的那个素数。
[color=red]解题思路[/color]:我们先不对这个问题进行进一步数学上的分析,直接想怎么用蛮力法去解决它。显然,我们可以先从9位的pandigital从大大小进行尝试,如果找到了一个素数,那么这个数就是所求;否则,再对8位的pandigital从大到小进行尝试……如此直到找到一个素数为止,这个素数就是问题的答案。
  下面就是依照这个思路写的代码:
import eastsun.math.Util._

object Euler041 extends Application {


def isPrime(n:Int) = 2.to(math.sqrt(n).toInt).forall{ n%_ != 0}

var buf = Array(9,8,7,6,5,4,3,2,1)
var idx = 0
var res = 0
while(res == 0){
var src = buf.slice(idx,buf.length)//subArray(idx,buf.length)
do{
var num = src.foldLeft(0){ _*10 + _ }
if(isPrime(num)) res = num
}while(res == 0&&prevPermutation(src))
idx += 1
}
println(res)
}

  虽然是很野蛮的方法,但这段代码已经够用了,只需要2秒左右就能得到答案。不过只要再简单思考一下,就可以瞬时找到答案。如果你高中数学还学得马马虎虎,应该不难验证:[color=green]一个数能被3整除当且仅当这个数的各位数字之和能被3整除[/color]。这样就可以知道9位的pandigital里面不可能有素数,因为1+2+3+..+9 = 45能被三整除,同样可以知道8位的pandigital里面也没有素数。所以事实上我们从7位的pandigital试起就可以。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 可以使用Python语言来实现这个功能。 首先,我们需要去除字符串中的重复字母并按字典排列。可以使用Python中的set和sorted函数来实现: ```python s = "hello world" s = sorted(set(s)) print(s) # [' ', 'd', 'e', 'h', 'l', 'o', 'r', 'w'] ``` 接下来,我们需要使用递归程序调用来实现这些字母的所有排列顺序显示。可以使用递归函数来实现: ```python def permutation(s, prefix=""): if len(s) == : print(prefix) else: for i in range(len(s)): permutation(s[:i] + s[i+1:], prefix + s[i]) ``` 这个函数的作用是将字符串s中的每个字符依次取出,放到prefix字符串的末尾,然后递归调用permutation函数,直到s为空字符串,此时输出prefix字符串。 最后,我们将两个函数组合起来,实现完整的功能: ```python def permutation(s, prefix=""): if len(s) == : print(prefix) else: for i in range(len(s)): permutation(s[:i] + s[i+1:], prefix + s[i]) s = "hello world" s = sorted(set(s)) permutation(s) ``` 输出结果为: ``` dehlorw dehlowr dehlrow dehlrwo dehlwor dehlwro deholor deholro dehowlr dehowrl dehrlow dehrlwo dehrolo dehrolo dehrowl dehrwlo dehrwol dehwlor dehwlro dehwolr dehworl delhorw delhowr delhrow delhrwo delhwor delhwro delohrw delohwr delorhw delorwh delowhr delowrh delrhwo delrhow delrohw delrowh delrwho delrwoh delwhor delwhro delwohr delworh deohlrw deohlwr deohrlw deohrwl deohwlr deohwrl deolhrw deolhwr deolrhw deolrwh deolwhr deolwrh deorhlw deorhwl deorlhw deorlwh deorwhl deorwlh deowhlr deowhrl deowlhr deowlrh deowrhl deowrlh derhlow derhlwo derholw derhowl derhwlo derhwol derlhwo derlhow derlohw derlowh derlwho derlwoh derohlw derohwl derolhw derolwh derowhl derowlh derwhlo derwhol derwlho derwloh derwohl derwolh dewhlor dewhlro dewholr dewhorl dewlrho dewlroh dewlhor dewlhro dewlohr dewlorh dewlrho dewlroh dewohlr dewohrl dewolhr dewolrh deworhl deworlh dewrhlo dewrhol dewrlho dewrloh dewrohl dewrolh dloehrw dloehwr dloerhw dloerwh dloewhr dloewrh dlorhew dlorhwe dlorehw dlorewh dlorwhe dlorweh dlowehr dlowerh dlowher dlowhre dlowreh dlowrhe dlrehwo dlrehow dlreohw dlreowh dlrewho dlrewoh dlrheow dlrhewo dlrhoew dlrhowe dlrhweo dlrhwoe dlroehw dlroewh dlrohew dlrohwe dlroweh dlrowhe dlwehor dlwehro dlweohr dlweorh dlwerho dlweroh dlwhero dlwheor dlwhore dlwhroe dlwoehr dlwoerh dlwoher dlwohre dlworeh dlworhe dloehrw dloehwr dloerhw dloerwh dloewhr dloewrh dlorhew dlorhwe dlorehw dlorewh dlorwhe dlorweh dlowehr dlowerh dlowher dlowhre dlowreh dlowrhe doelhrw doelhwr doelrhw doelrwh doelwhr doelwrh doerhlw doerhwl doerlhw doerlwh doerwhl doerwlh doehlrw doehlwr doehrlw doehrwl doehwlr doehwrl doelhrw doelhwr doelrhw doelrwh doelwhr doelwrh doerhlw doerhwl doerlhw doerlwh doerwhl doerwlh doewhlr doewhrl doelrhw doelrwh doelwhr doelwrh doerhlw doerhwl doerlhw doerlwh doerwhl doerwlh dowehlr dowerhl dowelhr dowelrh dowerhl dowerlh dowhler dowhlre dowhoer dowhore dowhrle dowhroe dowlehr dowlerh dowlher dowlhre dowlreh dowlrhe dowoehr dowoerh dowohre dowohre doworeh doworhe dowrheo dowrhoe dowrleo dowrloe dowroeh dowrole dwelhor dwelhro dwelohr dwelorh dwelrho dwelroh dweohlr dweohl dweorhl dweorlh dweolhr dweolrh dwerhlo dwerhol dwerlho dwerloh dwerohl dwerolh dwlhreo dwlhero dwlhoer dwlhore dwlrheo dwlrohe dwloehr dwloerh dwlohre dwlorhe dwloreh dwlorhe dwlreho dwlreoh dwlrheo dwlrhoe dwlroeh dwlrohe dwoehlr dwoerhl dwoelhr dwoelrh dwoerhl dwoerlh dwohler dwohlre dwohoer dwohore dwohrle dwohroe dwolehr dwolerh dwolher dwolhre dwolreh dwolrhe dwooehr dwooerh dwoohre dwoohre dwooreh dwoorhe dworheo dworhoe dworleo dworloe dworoeh dworole ehllo world ehlloowrd ehlloowrl ehllorowd ehllorow ehllo rwd ehllo rwo ehllo wodr ehllo word ehllo wrod ehllo wrdo ehlloowdr ehlloowrd ehlloorwd ehlloorw ehlloowr ehllo rwd ehllo rwo ehllo wodr ehllo word ehllo wrod ehllo wrdo ehlrowd ehlrow ehlrwd ehlrwo ehlrodw ehlrowd ehlrow ehlrwd ehlrwo ehlrodw ehlrowd ehlrow ehlrwd ehlrwo ehlrodw ehlrowd ehlrow ehlrwd ehlrwo ehlrodw ehlrowd ehlrow ehlrwd ehlrwo ehlrodw ehlrowd ehlrow ehlrwd ehlrwo ehlrodw ehlrowd ehlrow ehlrwd ehlrwo ehlrodw ehlrowd ehlrow ehlrwd ehlrwo ehlrodw ehlrowd ehlrow ehlrwd ehlrwo ehlrodw ehlrowd ehlrow ehlrwd ehlrwo ehlrodw ehlrowd ehlrow ehlrwd ehlrwo ehlrodw ehlrowd ehlrow ehlrwd ehlrwo ehlrodw ehlrowd ehlrow ehlrwd ehlrwo ehlrodw ehlrowd ehlrow ehlrwd ehlrwo ehlrodw ehlrowd ehlrow ehlrwd ehlrwo ehlrodw ehlrowd ehlrow ehlrwd ehlrwo ehlrodw ehlrowd ehlrow ehlrwd ehlrwo ehlrodw ehlrowd ehlrow ehlrwd ehlrwo ehlrodw ehlrowd ehlrow ehlrwd ehlrwo ehlrodw ehlrowd ehlrow ehlrwd ehlrwo ehlrodw ehlrowd ehlrow ehlrwd ehlrwo ehlrodw ehlrowd ehlrow ehlrwd ehlrwo ehlrodw ehlrowd ehlrow ehl ### 回答2: 首先,我们需要编写一个程序来去除字符串中的重复字母并按字典排列。可以使用一个集合来存储字符串中的字符,这样可以自动去除重复的字符。然后,将集合中的字符按字典序排序,可以使用内置的排序函数或者自己实现一个排序算法。 以下是一个简单的实现示例: ``` python def remove_duplicates_and_sort(string): # 去除重复字母 unique_chars = set(string) # 按字典序排序 sorted_chars = sorted(unique_chars) # 将字符拼接成字符串并返回 return ''.join(sorted_chars) ``` 接下来,我们可以使用递归来生成所有可能的排列顺序。可以使用回溯法来实现递归。首先从字符串中选择一个字符作为当前位置的字符,然后递归地生成剩余字符的所有排列顺序,并将当前位置的字符依次插入到每个排列中的不同位置。 以下是一个简单的递归回溯实现示例: ``` python def get_permutations(string): if len(string) <= 1: return [string] # 递归生成剩余字符的排列顺序 permutations = get_permutations(string[1:]) char = string[0] results = [] # 插入当前字符到每个排列中的不同位置 for permutation in permutations: for i in range(len(permutation) + 1): new_permutation = permutation[:i] + char + permutation[i:] results.append(new_permutation) return results ``` 最后,我们可以将去重排序后的字符串作为输入,调用`get_permutations`函数来获取所有可能的排列顺序,并进行显示。 ``` python input_string = input("请输入一条英文字符串:") removed_duplicates = remove_duplicates_and_sort(input_string) permutations = get_permutations(removed_duplicates) for permutation in permutations: print(permutation) ``` 这样,我们就可以实现通过递归程序调用来显示输入字符串中所有字符的排列顺序。 ### 回答3: 首先,我们需要编写一个程序,将输入的字符串中的重复字母去除并按字典排列。可以采用以下的步骤完成: 1. 将输入的英文字符串转换为小写字母,方便处理。 2. 创建一个空的集合,用于存储去重后的字母。 3. 遍历字符串中的每个字母,将其添加到集合中。 4. 将集合转换为列表,并按字典序排序。 5. 将列表中的字母连接成一个新的字符串,作为去重和排序后的结果。 以下是实现上述步骤的Python代码: ```python def remove_duplicate_letters(string): string = string.lower() unique_letters = set() for letter in string: unique_letters.add(letter) sorted_letters = sorted(list(unique_letters)) result = ''.join(sorted_letters) return result ``` 接下来,我们可以编写一个递归程序,根据排列的定义,依次输出所有的排列顺序。 递归程序可以按照以下的步骤实现: 1. 如果输入的字符串为空,直接返回空列表。 2. 如果字符串只有一个字母,将其作为唯一的排列结果,返回包含该字母的列表。 3. 否则,将字符串第一个字母与剩余部分的所有排列进行组合,即将第一个字母插入到所有排列结果的各个位置,并递归调用自身计算剩余部分的排列。将每个组合的结果都添加到最终的排列结果列表中。 以下是实现上述步骤的Python代码: ```python def get_permutations(string): if not string: return [] if len(string) == 1: return [string] permutations = [] for i in range(len(string)): first_char = string[i] remaining_chars = string[:i] + string[i+1:] for sub_permutation in get_permutations(remaining_chars): permutations.append(first_char + sub_permutation) return permutations ``` 最后,我们可以将这两个函数结合起来,实现输入一条英文字符串,先通过程序去除字符串中重复字母并按字典排列,然后通过递归程序调用形式实现这些字母的所有排列顺序显示的功能。 以下是结合两个函数的Python代码: ```python def remove_duplicate_letters(string): # 省略去重和排序的代码,参考之前的示例 def get_permutations(string): # 省略排列的代码,参考之前的示例 def display_permutations(string): sorted_string = remove_duplicate_letters(string) permutations = get_permutations(sorted_string) for permutation in permutations: print(permutation) ``` 这样,当调用`display_permutations(string)`时,就可以输出输入字符串中字母的所有排列顺序

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值