全排列解法总结(Java语言)

最近在准备蓝桥杯,所以今天想对全排列的一些解法进行总结,这样也方便于以后的复习。

<font size="6px">样例问题</font>
      这里我选择了一个较为容易理解的题目进行全排列的总结。题目是输入一个字符串,例如"abcd",通过全排列得出该字符串中字符的所有组合方式。
<font size="6px">
一、迭代法</font>

      思路分析:这题使用的是迭代法,我的思路是首先创建一个old_list来存储上一次循环中保存的所有字符串。然后对old_list进行初始化,将字符串的0号位添加到old_list中,这其实也相当于完成了第一次循环,将第一次循环得到的所有字符串添加到old_list中。之后从1号位对字符串x进行遍历,取出i号位上的值赋值给临时变量temp并创建一个new_list来存放当次循环得到的字符串。这里必须要创建一个new_list来存放当次循环得到的字符串,不能直接存入到old_list,这样的话会造成重复。然后就是循环遍历old_list中的字符串,对于上一次循环得到的字符串,当次循环的字符总共有三种插入方式,分别是:1、在字符串的前面加上字符 2、在字符串的末尾加上字符 3、在字符串的中间加上字符。当遍历结束后,将new_list赋值给old_list,这样便于下一次循环。最后输出结果。

在这里插入图片描述

public static void main(String[] args) {
        String x = "abcd";
        全排列总结 a = new 全排列总结();
        ArrayList<String> sort1 = a.sort1(x);
        System.out.println(sort1.size());
        System.out.println(sort1);
    }
    //迭代法
    public static ArrayList<String> sort1(String x) {
        ArrayList<String> old_list = new ArrayList<>();                 //创建一个List,用来存放上一次循环完成后的字符串
        
        old_list.add(x.charAt(0) + "");                                 //初始化,将0号位的字符存入list
        
        for (int i = 1; i < x.length(); i++) {                          //从一号位开始遍历字符串
            String temp = x.charAt(i) + "";
            ArrayList<String> new_list = new ArrayList<>();             //创建新的list来存放新一轮的字符串
            
            for (String old : old_list) {                               //循环遍历old_list,取出所有字符串
                new_list.add(temp + old);                               //第一种情况,在字符串的前面加上字符
                new_list.add(old + temp);                               //第二种情况,在字符串的末尾加上字符
                for (int j = 1; j < old.length(); j++) {
                    new_list.add(old.substring(0, j) + temp + old.charAt(j));   //第三种情况,在字符串的中间加上字符
                }
            }
            
            old_list = new_list;                                        //将new_list中的字符串存给old_list,开始下一次循环
        }
        return old_list;                                                //返回结果

    }

<font size="6px">
二、递归法</font>

      思路分析:这题使用的是递归法,是迭代法的改编版。因为是递归法,所以肯定要将一部分的事情交给现在做,另一部分交给递归去完成。所以我们可以先将字符串x的0~n-1号位上的字符排列出所有情况,然后再将n号位上的字符插入到所有情况中,这样就完成了 全排列。如下面代码所示。先创建一个old_list来存放第n个字符插入后的所有情况。然后调用递归,获取0~n-1位上字符串的所有排列情况。然后将第n号位上的字符插入进去即可。插入方法有三种情况,同迭代法是一样的。最后返回结果

public static void main(String[] args) {
        String x = "abcd";
        全排列总结 a = new 全排列总结();
        ArrayList<String> arr = new ArrayList<>();
        ArrayList<String> sort2 = a.sort2( x, x.length()-1, arr);
        System.out.println(sort2.size());
        System.out.println(sort2);
    }
    // 递归法
    public ArrayList<String> sort2(String x, int n, ArrayList<String> arr) {
        if (n == 0) {                                       //为递归设置出口
            arr.add(x.charAt(0) + "");                      //初始化list
            return arr;
        }
        ArrayList<String> old_list = new ArrayList<>();         //为n号位字符创建一个list
        ArrayList<String> new_list = sort2(x, n - 1, arr);      //调用递归,得到1~n-1号位已经排列好全部情况的list

        for (String old : new_list) {                           // 循环遍历new_list,将字符串n号位的字符插入到全部情况中
            old_list.add(x.charAt(n) + old);                    // 第一种情况,在字符串的前面加上字符
            old_list.add(old + x.charAt(n));                    // 第二种情况,在字符串的末尾加上字符
            for (int j = 1; j < old.length(); j++) {
                old_list.add(old.substring(0, j) + x.charAt(n) + old.charAt(j)); // 第三种情况,在字符串的中间加上字符
            }
        }

        return old_list;                                        //返回结果
    }

<font size="6px">
三、交换法</font>

      思路分析:这题使用的是交换法,运用了回溯的思想。首先是将字符串转换为字符数组,并排列。然后调用sort3方法,每次都循环遍历从k号位到字符串末尾的每一个字符。swap(arr,k,i)意味将第i号位上的的值,交换到第k号位。然后递归调用,直到当k==arr.length时就将排列好的arr添加到全局变量res中,完成一次排列。这里调用完之后必须swap(arr,i,k)将数组复原,然后进行下一次循环。最后得到结果

在这里插入图片描述

    public static void main(String[] args) {
        String x = "abcd";
        全排列总结 a = new 全排列总结();
        char[] array = a.toArray(x);
        ArrayList<String> sort3 = a.sort3(array, 0);
        System.out.println(sort3.size());
        System.out.println(sort3);
    }
    // 交换法
    public char[] toArray(String x) {                           //将字符串转换为字符数组
        char[] arr = x.toCharArray();
        Arrays.sort(arr);
        return arr;
    }
    
    ArrayList<String> res = new ArrayList<>();                  //定义一个全局变量来存放所有排列情况

    public ArrayList<String> sort3(char[] arr, int k) {
        if (k == arr.length) {
            res.add(new String(arr));
        }
        for (int i = k; i < arr.length; i++) {                  //每次都循环遍历每一个未被遍历过的数
            swap(arr, k, i);                                    //将第i号位上的值和k号位上的值交换
            
            sort3(arr, k + 1);                                  //从k+1号位开始调用递归,知道遍历完所有数
            
            swap(arr, i, k);                                    //回溯,将字符串复原
        }
        return res;

    }

    public void swap(char[] arr, int k, int i) {                //交换位置
        char temp = arr[k];
        arr[k] = arr[i];
        arr[i] = temp;
    }

<font size="6px">
四、前缀法</font>

      思路分析:这题使用的是前缀法,我为本题加了一个条件(字符串必须有序),在全排列中,按照顺序排列,并且输出第num个排列好的数。Main方法调用sort4(),进入for循环,每次都遍历数组全部,然后遇到if语句,判断数组中某字符的出现次数如果大于在字符串中出现的次数,那说明需要把字符添加到prefix中。最后当字符串prefix的长度等于数组的长度时,即一次排列完成,总数加一。当cnt==num时则输出结果。

    public static void main(String[] args) {
        String x = "abcd";
        全排列总结 a = new 全排列总结();
        a.sort4("",x.toCharArray());
    }
    int cnt=0;                                      //总数
    final int num=3;                                //需要获得第几个的值
    //前缀法
    public void sort4(String prefix,char[] arr) {
        if(prefix.length()==arr.length) {                       //递归出口
            cnt++;
            if(cnt==num) {                                      //当字符串prefix的长度等于数组的长度时
                System.out.println(prefix);                     //输出结果
                System.exit(0);;
            }
        }
        for(int i=0;i<arr.length;i++) {                             //每次都遍历数组全部元素
            char ch=arr[i];
            if(count(prefix.toCharArray(),ch)<count(arr,ch)) {      //判断数组中某字符的出现次数如果大于在字符串中出现的次数
                sort4(prefix+ch,arr);
            }
        }
    }
    
    public int count(char[] arr,char ch) {                  //判断字符在数组中出现的次数
        int count=0;
        for(int i=0;i<arr.length;i++) {
            if(arr[i]==ch) {
                count++;
            }
        }
        return count;
    }
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,542评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,596评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,021评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,682评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,792评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,985评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,107评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,845评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,299评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,612评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,747评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,441评论 4 333
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,072评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,828评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,069评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,545评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,658评论 2 350

推荐阅读更多精彩内容

  • 官网 中文版本 好的网站 Content-type: text/htmlBASH Section: User ...
    不排版阅读 4,374评论 0 5
  • 写在前面的话 代码中的# > 表示的是输出结果 输入 使用input()函数 用法 注意input函数输出的均是字...
    FlyingLittlePG阅读 2,743评论 0 8
  • 1)这本书为什么值得看: Python语言描述,如果学的Python用这本书学数据结构更合适 2016年出版,内容...
    孙怀阔阅读 12,459评论 0 15
  • 第五章******************************************************...
    fastwe阅读 673评论 0 0
  • CGI 一. CGI是什么CGI,全称是Common Gateway Interface,翻译过来就是“通用网关接...
    Uchiha_Ponny阅读 515评论 1 3