算法之字符串全排列(Java 递归与非递归的实现)

问题描述

实现字符串的全排列,比如 用户输入“abcd”,则会输入如下4!个字符串

a b c d 
....
....
d c b a 

实现方式两种:

  • 递归
  • 非递归

工具类方法

/**
* 遍历打印 字符串
* @param str
*/
private static void printCharArr(char[] str) {
   for (char c :
           str) {
       System.out.print(c + " ");
   }
   System.out.print("\n");
}

递归实现

通过方法的递归调用 ,将问题规模降低。

/**
 * 打印字符串
 * @param str
 * @param index
 */
public static void  printAllStrs(char[] str,int index){
    if(index==str.length-1){
        //打印当前数组
        printCharArr(str);
        return;
    }

    for (int i = index; i < str.length; i++) {
        if(isCanSwap(index,i,str)){
            //将index之后的某个元素与index位置的原生进行交换
            //然后打印全排列
            swap(i,index,str);
            printAllStrs(str,index+1);
            //还原数据的位置
            swap(i,index,str);
        }
    }
}

/**
 * 去重
 * @param start
 * @param start
 * @param str
 * @return
 */
private static boolean isCanSwap(int start, int end, char[] str) {
    char target = str[end];
    while (--end>=start){
        if(str[start]== target)
            return false;
    }
    return true;
}

/**
 * 交换位置
 * @param start
 * @param end
 * @param str
 */
public static void swap(int start,int end, char[] str){
    char tmp = str[start];
    str[start] = str[end];
    str[end] = tmp;
}

非递归

/**
* 
* 实现的思想是 从最小值到最大值,依次递增
* 
* 递增实现的步骤如下:
* 
* 步骤: 假设输入的数组为 s = '15976'
* 1. 首先排序(从小到大)
* 2. 从后往前找到第一个递增位置的元素 i (比如'15976' 的最后一个递增位置索引是 1)
* 3. 然后找到从第i位置往后找,找到一个比s【i】大的,且最小的元素s[j] (改元素的索引位置j).
* 4. 将s[j]与s[i]交换位置
* 5. 将i+1之后的元素进行翻转
* 6. 直到不存在递增的元素位置而止
* 
* 全排列 非递归
*      12345 -> 12354 -> 12354
*      12354 -> 124 53 -> 12435
*
*      21534 -> 2154 3->  21543
*      21543 -> 2 3541 -> 23145
*
*
* @param str
*/ 
public static void printAllStrs(char[] str){
    while (true){
        //先找到最后一个递增的位置
        int i = str.length-2;
        while (i>=0&&str[i]>str[i+1]){
            i--;
        }
        if(i<0){
            break;
        }
        char tmp = str[i];
        //将该位置数据和 右侧比起大的最小值进行交换
        char smallerValue = str[i+1];
        int smallerIndex= i+1;
        for (int start = i+1;start<str.length;start++){
            if(str[start]>tmp&&smallerValue>str[start]){
                smallerIndex = start;
                smallerValue = str[start];
            }
        }
        //交换
        str[i] = str[smallerIndex];
        str[smallerIndex] = tmp;
        int startIndex = i+1;

        int postPtr = str.length-1;
        //将该位置的往后的数据进行翻转
        while (startIndex<postPtr){
            char tmp2 = str[startIndex];
            str[startIndex] =str[postPtr];
            str[postPtr] = tmp2;
            startIndex++;
            postPtr--;
        }
        //打印数据
        printCharArr(str);
    }
}

你可能感兴趣的:(算法)