zoukankan      html  css  js  c++  java
  • 全排列算法(递归和字典)

    一个算法命题:给定字符串S[0…N-1],设计算法,枚举S的全排列。如:123,全排列就是:123,132,213,231,312,321

    个人愚昧,搞了一天半,才终于把字典排列搞出来,看不到大神写的代码,我的代码还有很多优化之处,先记录下,递归现在还是有点蒙。

     


    java代码:递归实现(考虑有重复的字符)

    以字符串1234为例:
    1 – 234
    2 – 134
    3 – 214
    4 – 231
    如何保证不遗漏: 每次递归前,保证1234的顺序不变。

     1 package stringtest;
     2 import java.util.ArrayList;
     3 import java.util.Collections;
     4 
     5 /**题目描述
     6     输入一个字符串,按字典序打印出该字符串中字符的所有排列。
     7     例如输入字符串abc,则打印出由字符a,b,c所能排列出来的所有字符串abc,acb,bac,bca,cab和cba。
     8     输入描述:
     9     输入一个字符串,长度不超过9(可能有字符重复),字符只包括大小写字母。
    10  * 
    11  * 
    12  * @author Administrator
    13  *
    14  */
    15 public class FullArray {
    16 
    17     public static void main(String[] args) {
    18         FullArray fa = new FullArray();
    19         String str = "abc";
    20         ArrayList<String> arrayList = fa.Permutation(str);
    21         for (String string : arrayList) {
    22             System.out.println(string);
    23         }
    24     }
    25 
    26     /**
    27      * 思路:利用递归的思想。来实现
    28      * 先让a第一位:剩余bcd做全排列
    29      * 先让b第一位:剩余acd做全排列
    30      * 先让c第一位:剩余abc做全排列
    31      * 先让d第一位:剩余abc做全排列
    32      * 
    33      * @param str
    34      * @return
    35      */
    36     ArrayList<String> list = new ArrayList<>();
    37     public ArrayList<String> Permutation(String str) {
    38         char[] array = str.toCharArray();
    39         permutaionTest(array,0,str.length()-1);
    40         Collections.sort(list);
    41         return list;
    42     }
    43     
    44     public void permutaionTest(char[] array,int start,int end){
    45         //递归退出条件
    46         if(array.length<1){
    47             return;
    48         }
    49         //如果start和end不相等,说明完成一次排序
    50         if(start==end){
    51             String val = new String(array);
    52            //这里也是判断元素重复情况(方式一)
    53             if (!list.contains(val))
    54                 list.add(val);
    55         }else{
    56             //回溯法,每次固定一个元素在最前面,后面元素进行全排列
    57             for (int i = start; i <= end; i++) {
    58        
    59                //考虑有重复元素的情况(方式二)
    60                 boolean flag = true;
    61                 for (int j = start; j < i; j++) {
    62                     if(array[j] == array[i]){//这里吧i换成end也行
    63                         flag = false;
    64                     }
    65                 }
    66                 
    67                 //有重复元素就跳过大循环,下一个比较
    68                 if(flag){
    69                     swap(array,start,i);
    70                     permutaionTest(array,start+1,end);
    71                     swap(array,i,start);
    72                 }
    73             }
    74         }
    75     }
    76 
    77     private void swap(char[] array, int start, int i) {
    78         if(start!=i){
    79             char tmp = array[start];
    80             array[start] = array[i];
    81             array[i] = tmp;
    82         }
    83     }
    84 }

    java代码:字典序排列(考虑有重复的字符)

    全排列的非递归算法:整理成算法语 步骤:后找、小大、交换、翻转——
     后找:字符串中最后一个升序的位置i,即S[k]>S[k+1](k>i),S[i]<S[i+1];
     查找(小大):S[i+1…N-1]中比Ai大的最小值(补充:根据规律,好像只要从右往左找第一个比Ai大的值就行。)
     交换:Si,Sj;
     翻转:S[i+1…N-1]


    个人总结:以926520为例
    ①:字符串从后往前找,找到第一个降序的值为2,位置为1
    ②:然后找出2和后面比2大的数的最小值为5(补充:从右往左找第一个比2大的值为5。)
    ③:2和找出的5进行位置交换
    ④:把2后面所有的数进行翻转

    最后大功告成:
    第一步:先把字符串进行全排序

     1 package com.qyzx.string;
     2 
     3 import java.util.ArrayList;
     4 import java.util.Arrays;
     5 
     6 public class AllArray2 {
     7 
     8     public static void main(String[] args) {
     9         String str = "1212";
    10         char[] arr = str.toCharArray();
    11         //先对数组进行重小到大进行排序
    12         Arrays.sort(arr);
    13         fullArray(arr,0,arr.length-1);
    14     }
    15 
    16     /**
    17      * 该方法是对字符串进行全排列
    18      * 
    19      * @param arr
    20      * @param i
    21      * @param j
    22      */
    23     private static boolean fullArray(char[] arr, int start, int end) {
    24         if(end<1){
    25             return true;
    26         }
    27         while(true){
    28             System.out.println(arr);
    29             //①:从后往前找,找出第一个降序的值
    30             int first = end;
    31             for (int i = end; i >= 1; i--) {
    32                 if(arr[i-1]<arr[i]){
    33                     first = i-1;
    34                     break;
    35                 }else if(i==1){
    36                     //说明已经排好序了,没有降序的值。
    37                     return false;
    38                 }
    39             }
    40 //            System.out.println("第一个降序的值n:"+arr[first]+",first下标:"+first);
    41             //②:找出first后面比first大的数
    42             ArrayList<Integer> list = new ArrayList<>();
    43             for (int i = first+1; i < end+1; i++) {
    44                 if(arr[first]<arr[i]){
    45                     list.add(i);
    46                 }
    47             }
    48             //比first大的数的最小值
    49             int min = list.get(0);
    50             for (int i = 1; i < list.size(); i++) {
    51                 if(arr[min]>arr[list.get(i)]){
    52                     min = list.get(i);
    53                 }
    54             }
    55 //            System.out.println("比n大的最小值m:"+arr[min]+",min下标:"+min);
    56             //③:然后交换min和first的位置
    57             swap(arr,min,first);
    58             //④:因为交换了位置,所以现在的min就是之前的first,把min后面所有的字符串进行反转
    59 //            System.out.println("n后面数字进行翻转前:"+String.valueOf(arr));
    60             resver(arr,first+1,end);
    61 //            System.out.println("n后面数字进行翻转后:"+String.valueOf(arr));
    62         }
    63     }
    64     
    65     //实现arr数组的s位置到end位置的翻转
    66     private static void resver(char[] arr, int start, int end) {
    67         while(start<end){
    68             //可以把最后赋值给前面
    69             char temp1 = arr[start];
    70             arr[start++] = arr[end];
    71             arr[end--] = temp1;
    72         }
    73     }
    74 
    75     //进行元素之间交换位置
    76     public static void swap(char[] arr,int from ,int to){
    77         char s = arr[from];
    78         arr[from] = arr[to];
    79         arr[to] = s;
    80     }
    81     
    82 }
  • 相关阅读:
    界面控件DevExpress Blazor UI组件v20.2新版亮点:集成Visual Studio
    如何打印超长图片
    使用you-get库下载视频自动化
    数组求最值和平均数的算法
    如何删除git所有提交历史
    计算机图形学应知应会
    通过终端登录FTP服务器的方式
    局域网内通过ARP欺骗获取他人账号密码
    如何在局域网下用他人的流量上网
    XAMPP下的项目进行内网穿透时的注意点
  • 原文地址:https://www.cnblogs.com/xiongmozhou/p/10483463.html
Copyright © 2011-2022 走看看