`
Eastsun
  • 浏览: 304932 次
  • 性别: Icon_minigender_1
  • 来自: 天津
社区版块
存档分类
最新评论

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

阅读更多
  因为最近在做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试起就可以。
6
0
分享到:
评论
1 楼 naff 2008-06-25  
嗯,不错,收藏了...

相关推荐

    快速批量生成排列:获取输入向量的下一个字典顺序排列块-matlab开发

    我只是将 C++ STL 函数 next_permutation 包装在 Mex 中。 若要使用,请先使用“ mex nextperms.cpp”为您的系统编译。 有关文档,请参阅 ... 它们按字典顺序生成(根据 STL 规范)。 传入的初始向量不包含在输出

    算法之排列算法与组合算法详解

    1. 前言 本文介绍了常用的排列组合算法,包括全排列算法,全组合...生成给定全排列的下一个排列 所谓一个的下一个就是这一个与下一个之间没有字典顺序中相邻的字符串。这就要求这一个与下一个有尽可能长的共同前缀,

    nthperm:直接计算第 N 个词典排列-matlab开发

    给定一个已排序的输入向量 V 和正整数 n,将 V 重新排列为其第 N 个词典排列。 V 必须排序,否则行为将不正确。 然而,Sorted 具有灵活的含义;... NTHPERM 按字典顺序生成排列以匹配 NEXTPERMS,它基于 C++ STL next_

    合并文本文件生成pdf

    1.把文本文件按名称的字典顺序排列好 2.把这些文本文件拖动到exe上 3.在文件夹中得到一个out.pdf的文件 内部使用的是仿宋10号字体 页面使用的A4纵向排列,边距:上7mm,左右各5mm 文件与文件内容由分割线分开 分割线上...

    Permutations:置换算法的实现。 管理置换索引的算法的实现。 测试置换算法的基准

    还包括Sani Singh Huttunen置换算法实现,这是按字典顺序查找所有置换最快的方法。 在单个线程中实现置换堆算法(生成所有置换的最快方法)。 一个算法的实现,该算法为每个排列和反向索引。 最快的多线程实现算法...

    permutation:排列

    可以同时使用置换器调用Permutator.Next()以字典顺序返回下一个排列。如果生成了所有排列,则返回错误func ( p * Permutator ) Next ()( interface {}, error ) 调用Permutator.NextN()以词法顺序返回下一个n...

    SuQ-Projekt:软件架构和质量保证项目任务

    一个词的所有不同定义必须按有意义的顺序排列(例如输入顺序)。 必须接受“停用词”列表。 这些词不能在索引中(作为关键字)出现。 必须提供一个界面,用户可以通过该界面查找单词或搜索包含特定术语的所有定义...

    合并多个图片文件到pdf格式

    1.把要合并的图片文件按名称字典顺序排列好 2.把这个图片文件拖到此exe上面 3.在相同文件夹生成一个新的pdf文件 由Go语言编写 不得用于违法行为 仅限个人使用

    git-buildnumber:git-buildnumber提供了一种从git存储库生成标准化内部版本号的方法

    关于git-buildnumber git-build...用例git-buildnumber以人类可读的形式生成标准化版本字符串,以与滚动发布周期一起使用,或者在需要按字典顺序排列的内部版本号时使用。 由git-buildnumber生成的版本字符串并不意味着

    anagram-solver:从字典创建字谜类

    字谜问题描述目标是找到字典中的所有字谜。 编写一个程序,读取由小写字母组成的单词“字典”,每行一个单词,并计算所有字谜类。... 按字母顺序对单词进行排序以生成键。 将密钥散列到表中以找到一个空槽来存储它。 如

    leetcode刷题免费吗-Node-Sort-Algorithms:基于众所周知的算法制作的Node.js和javascript排序库包括:

    最常用的顺序是数字顺序和字典顺序。 高效排序对于优化其他算法(例如搜索和合并算法)的使用很重要,这些算法要求输入数据在排序列表中; 它通常也可用于规范化数据和生成人类可读的输出。 更正式地说,输出必须...

    2024年第十五届蓝桥杯Python A组省赛题目+参赛代码

    贪心,按从左到右顺序处理左半边,能两个一起就两个一起,不能就单个 E:最大子串dp+最大生成树 F:用线性筛打质数表,然后记忆化搜索(win[i]表示长度为i时先手是否能赢,如果后继状态有输的,该状态就赢;否则输...

    Sorts:数据结构项目排序算法的可视化与比较

    最常用的顺序是数字顺序和字典顺序。 高效排序对于优化其他算法(例如搜索和合并算法)的使用很重要,这些算法要求输入数据在排序列表中; 它通常也可用于规范化数据和生成人类可读的输出。 更正式地说,输出必须...

    leetcode最难-Interview-Prep:规范面试问题及其解决方案

    以下是一些规范问题及其按重要性顺序列出的类: 递归(分而治之,回溯) 生成字符串的所有排列 生成字符串的所有唯一排列 在数学表达式中插入操作数以最大化表达式的值 24场 () 发电机组 生成所有 n 组平衡括号 给定...

    ACM巨全模板 .pdf

    11.求k维空间中离所给点最近的m个点,并按顺序输出(KD树) 12.LCA (两个节点的公共父节点) 动态规划: 1.LIS (最长上升子序列) 2.有依赖的背包 (附属关系) 3.最长公共子序列(LCS) 4.树形DP 5.状压DP-斯坦纳树 6.背包 7...

    Python Cookbook

    7.13 生成一个字典将字段名映射为列号 300 7.14 利用dtuple实现对查询结果的灵活访问 302 7.15 打印数据库游标的内容 304 7.16 适用于各种DB API模块的单参数传递风格 306 7.17 通过ADO使用Microsoft Jet 308 ...

    ACM 算法经典代码 数据结构经典代码

    1. 排列组合生成 59 2. 生成gray码 60 3. 置换(polya) 61 4. 字典序全排列 61 5. 字典序组合 62 6. 组合公式 62 十. 数值计算 63 1. 定积分计算(Romberg) 63 2. 多项式求根(牛顿法) 64 3. 周期性方程(追赶法) 66 ...

    易化的Python-易语言

    窗口设计完后按F5调试程序,窗口出现的时候代码也就自动生成好了,直接去Python里粘贴即可调试 Python模块EP.py 已封装200+常用命令 函数命名跟各种操作已尽量仿照精易模块 ,用起来还是熟悉的味道。 模块内已有函数...

Global site tag (gtag.js) - Google Analytics