因为最近在做
Project Euler上的题,里面涉及到的都是和数学有关问题,有一些数学概念会反复出现。比如判断一个数是否为素数,求一些元素的全排列之类。为了方便起见,我把一些功能写成函数,以便以后重复使用。这个帖子介绍的是将一些元素所有的全排列按
字典顺序依次生成的函数。
☆ Scala代码
/**
&#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
顾名思义,第一个
prevPermutation方法是将数组src重排成比当前字典顺序小的上一个排列。注意该方法的返回值为Boolean:如果存在比当前字典顺序小的排列,则重排src,并返回true;否则不影响src并返回false。还算有两点需要注意的地方:
1.该方法第二个参数view是implicit的,所以调用该方法的时候可以省略。只需要保证类型T有一个到Ordered[T]类型的隐式转换就可以了。
2.该方法第一个参数src中允许有重复的元素。
比如对于1,2,3,3,其所有排列按字典顺序排列为:
1233
1323
1332
2133
2313
2331
3123
3132
3213
3231
3312
3321
☆ 应用
下面就通过解决
Project Euler中的两个题来示范一下如何使用这两个API。
题目24:What is the millionth lexicographic permutation of the digits 0, 1, 2, 3, 4, 5, 6, 7, 8 and 9?
题目简介:将数字0, 1, 2, 3, 4, 5, 6, 7, 8 ,9的所有排列按字典顺序排序,求排在第1,000,000位的那个数字。(注意:从第一位记起)
当然这个题有更高效的解决方法,可以参看
Euler Project解题汇总 023 ~ 030。这里就使用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(""))
}
问题41:What is the largest n-digit pandigital prime that exists?
题目简介:一个数称为pandigital,如果它是数字1,2,……,n的一个排列。比如2143就是一个4位的pandigital。
现在求所有pandigital中最大的那个素数。
解题思路:我们先不对这个问题进行进一步数学上的分析,直接想怎么用蛮力法去解决它。显然,我们可以先从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秒左右就能得到答案。不过只要再简单思考一下,就可以瞬时找到答案。如果你高中数学还学得马马虎虎,应该不难验证:
一个数能被3整除当且仅当这个数的各位数字之和能被3整除。这样就可以知道9位的pandigital里面不可能有素数,因为1+2+3+..+9 = 45能被三整除,同样可以知道8位的pandigital里面也没有素数。所以事实上我们从7位的pandigital试起就可以。
分享到:
相关推荐
字典序法是一种按照特定顺序(通常是最小字典序)生成排列的算法。在字典序中,一个排列被认为小于另一个排列,如果在第一个不同的位置上,前者的数字小于后者的数字。例如,排列1234在字典序上小于1243。字典序法...
我只是将 C++ STL 函数 next_permutation 包装在 Mex 中。 若要使用,请先使用“ mex nextperms.cpp”为您的系统编译。 有关文档,请参阅 ... 它们按字典顺序生成(根据 STL 规范)。 传入的初始向量不包含在输出
在计算机科学中,排列是将有限集合的所有元素按一定顺序排列的方法。字典序是一种常见的排列排序方式,它按照字母表或数字顺序比较每个位置的元素。本篇将深入探讨如何使用C语言实现一个按照字典序生成排列的算法。 ...
**非字典排列**则是指不遵循特定字典顺序的排列方式,它更侧重于算法的效率和实现方式。 #### 三、研究背景与现状 在2005年,Donald E. Knuth在其著作中提出了一个关键问题:“最快的排列生成方式是什么?”这一...
字典序(Lexicographic Order),也称为字典顺序或字面顺序,是计算机科学中一个重要的概念,特别是在字符串处理、排序算法以及数据结构如字典树(Trie)等领域广泛应用。字典序的定义源自于我们查阅字典时按照字母...
标题所提到的"按字典顺序排列的第 k 个排列"是一个典型的数学问题,它涉及到组合数学和算法设计。这个问题的目标是找到一个 n 元素集合的所有排列,并按照字典顺序(即从小到大的顺序)找出第 k 个排列。 字典顺序...
5. **字典序全排列**:介绍如何按字典顺序生成所有排列。 6. **字典序组合**:解释如何按字典顺序生成所有组合。 #### 三、数据结构 1. **并查集**:介绍并查集的基本概念、实现方式及其应用场景。 2. **堆**:...
可能包括一个主函数,用于初始化和调用全排列函数,以及一个递归函数,负责生成排列和回溯。 7. **测试与验证**:为了确认算法的正确性,通常会编写一些测试用例,包括边界情况和一些预期的排列。"曲文杰—运行结果...
通过这样的算法,我们可以有效地生成一个序列的所有字典序排列。在实际应用中,这个方法常用于解决排列组合问题、优化搜索算法,或者在排序和比较字符串时使用。 在代码实现中,通常会用到循环和条件判断,以及数组...
在本场景中,我们关注的是字典序排列,这是一种特定的全排列顺序,按照字典顺序排列所有可能的组合。VC++是Microsoft开发的一种C++编程环境,它支持C++标准库,并提供了丰富的开发工具。 字典序排列算法通常用于...
在 Go 语言中,"permutation" 包是用来处理元素排列问题的一个工具,它允许开发者按字典顺序改变一组元素的顺序。这个包通常适用于那些需要遍历所有可能元素组合的算法或应用,例如数学计算、数据处理或者复杂的逻辑...
字典序排列是指按照字母表顺序或数字大小顺序生成所有可能的排列。在数字全排列中,这意味着从最小的排列开始,依次生成下一个更大的排列。例如,对于数字123,字典序排列会先生成123,然后是132,最后是213和231。...
字典序法是按照字典顺序生成全排列的一种方法。它首先将所有元素按照字典顺序排列,然后逐个尝试每个位置上的下一个元素,如果当前元素已经是最大值,则尝试下一个位置。在尝试过程中,如果发现无法找到下一个更大的...
字典序排列,也称为字典顺序或自然顺序,是按照字母表或数字的顺序对字符串或数组进行排序。在C++中,实现字典序排列通常涉及到比较每个元素的大小。"生成字典序排列.cpp"可能包含了对字符串数组进行字典序排序的源...
在数学和计算机科学中,**字典序求全排列**是指对一个集合的所有元素进行重新排序,使得每一次得到的新序列都能按照字典顺序(即字母表顺序或数字大小顺序)排列出来。例如,对于集合{1, 2, 3},其字典序全排列为:{...
字典序排列是指按照字典顺序生成所有可能的排列。在生成全排列时,字典序排列通常与堆栈或队列等数据结构结合使用。例如,可以使用一个堆栈来保存当前的排列状态,并在每次生成新的排列时将其压入堆栈,当堆栈非空时...
标题中的“字典法全排列”是指通过字典顺序(也称为升序)来生成一个序列的所有可能排列的方法。在组合数学中,全排列是指从n个不同元素中取出n个元素,按照一定的顺序排列,形成的所有可能的排列组合。在C语言中,...
描述中的“排列的字典序生成算法(自然解法)”则明确了我们要讨论的是如何实现一种能够自动生成字典序排列的算法。 字典序是指在给定字符集中,按照字符的自然顺序对字符串进行排序。例如,在英文中,按字母表顺序...
传统的排列生成算法多种多样,包括但不限于基于回溯技术的字典顺序生成算法、基于相邻元素交换的极小变化生成算法等。然而,这些算法往往存在一定的局限性,比如难以直接生成指定索引的排列,或者生成过程较为复杂。...
1. 字典全排列生成法:这种方法基于字典顺序,通过统计每个数字右侧比它小的数字数量来构建递增进位制中介数。例如,排列839647521的中介数为72642321。通过加100(4020的递增进位制数)可以得到新中介数72652011,...