题目描述

输入一个字符串,按字典序打印出该字符串中字符的所有排列。例如输入字符串abc,则打印出由字符a,b,c所能排列出来的所有字符串abc,acb,bac,bca,cab和cba。

输入描述:

输入一个字符串,长度不超过9(可能有字符重复),字符只包括大小写字母。

 

 

题目链接:

https://www.nowcoder.com/practice/fe6b651b66ae47d7acce78ffdd9a96c7?tpId=13&&tqId=11180&rp=1&ru=/activity/oj&qru=/ta/coding-interviews/question-ranking

 

 

分析:

第一个字符固定,子问题,从第二个字符起后面全排列……一直到只有一个字符。

第一个字符与第二个字符交换,子问题,从第二个字符起后面全排列……一直到只有一个字符。

……

存在重复字符问题:

     * *由于全排列就是从第一个数字起,每个数分别与它后面的数字交换,我们先尝试加个这样的判断——如果一个数与后面的数字相同那么这两个数就不交换了。
     * 例如abb,第一个数与后面两个数交换得bab,bba。然后abb中第二个数和第三个数相同,就不用交换了。
     * 但是对bab,第二个数和第三个数不 同,则需要交换,得到bba。
     * 由于这里的bba和开始第一个数与第三个数交换的结果相同了,因此这个方法不行。
     *
     * 换种思维,对abb,第一个数a与第二个数b交换得到bab,然后考虑第一个数与第三个数交换,此时由于第三个数等于第二个数,
     * 所以第一个数就不再用与第三个数交换了。再考虑bab,它的第二个数与第三个数交换可以解决bba。此时全排列生成完毕!

 

 

 

 

import java.util.ArrayList;
import java.util.HashSet;
import java.util.Collections;
public class Solution {
    ArrayList<String> arrs=new ArrayList<>(); 
    public ArrayList<String> Permutation(String str) {
        //""情况处理
        if("".equals(str)){
            return new ArrayList<>();
        }
        reSort(str.toCharArray(),0);
        Collections.sort(arrs);
        return arrs;
    }
    
    public void reSort(char[] arr,int pos){
        //结束条件,只剩最后一个元素
        if(pos == arr.length - 1){
            arrs.add(String.valueOf(arr));
            return;
        }
        //相同字符不需要换位置递归
        HashSet<Character> ss = new HashSet<>();
        for(int i = pos;i < arr.length;i++){
            //自己或者不同字符,递归排列所有组合
            if(i == pos || !ss.contains(arr[i])){
                ss.add(arr[i]);
                swap(arr,i,pos);
                //子问题:pos到右边界所有排列
                reSort(arr,pos+1);
                swap(arr,i,pos);
            }
        }
    }
    public void swap(char[] arr,int i,int j){
        char tmp = arr[i];
        arr[i] = arr[j];
        arr[j] = tmp; 
    }
}

 

 

 

 
/**
     * 2、字典序排列算法
     *
     * 可参考解析: http://www.cnblogs.com/pmars/archive/2013/12/04/3458289.html  (感谢作者)
     *
     * 一个全排列可看做一个字符串,字符串可有前缀、后缀。
     * 生成给定全排列的下一个排列.所谓一个的下一个就是这一个与下一个之间没有其他的。
     * 这就要求这一个与下一个有尽可能长的共同前缀,也即变化限制在尽可能短的后缀上。
     *
     * [例]839647521是1--9的排列。1—9的排列最前面的是123456789,最后面的987654321,
     * 从右向左扫描若都是增的,就到了987654321,也就没有下一个了。否则找出第一次出现下降的位置。
     *
     * 【例】 如何得到346987521的下一个
     * 1,从尾部往前找第一个P(i-1) < P(i)的位置
     * 3 4 6 <- 9 <- 8 <- 7 <- 5 <- 2 <- 1
     * 最终找到6是第一个变小的数字,记录下6的位置i-1
     *
     * 2,从i位置往后找到最后一个大于6的数
     * 3 4 6 -> 9 -> 8 -> 7 5 2 1
     * 最终找到7的位置,记录位置为m
     *
     * 3,交换位置i-1和m的值
     * 3 4 7 9 8 6 5 2 1
     * 4,倒序i位置后的所有数据
     * 3 4 7 1 2 5 6 8 9
     * 则347125689为346987521的下一个排列
     *
     * @param str
     * @return
     */

 

 

 

 

 

import java.util.ArrayList;
import java.util.HashSet;
import java.util.Collections;
public class Solution {
    ArrayList<String> arrs=new ArrayList<>(); 
    public ArrayList<String> Permutation(String str) {
        //""情况处理
        if("".equals(str)){
            return new ArrayList<>();
        }
        char[] arr = str.toCharArray();
        arrs.add(String.valueOf(arr));
        while(true){
            int pos = arr.length - 1;
            //找到第一个从右向左的降序位置
            while(pos >= 1 && arr[pos - 1] >=  arr[pos]){
                pos --;
            }
            //没有降序,说明全部查找完毕
            if(pos == 0){
                break;
            }
            //指向降序位置的那个较小的数
            pos--;
            int next = -1;
            //在pos右边找到第一个比arr[pos]大的数
            for(int i = arr.length - 1;i > pos;i--){
                if(arr[i] > arr[pos]){
                    next = i;
                    break;
                }
            }
            //交换pos与next的值
            swap(arr,next,pos);
            //翻转pos之后的值。pos之后由降序翻转后成为升序
            reverse(arr,pos + 1,arr.length - 1);
            //将该排列加入到结果集中
            arrs.add(String.valueOf(arr));
        }
        return arrs;
    }
    //翻转,[l,r]区间内排列翻转
    public void reverse(char[] arr,int l,int r){
        for(int i = l,j = r; i < j;i++,j--){
            char tmp = arr[i];
            arr[i] = arr[j];
            arr[j] = tmp;
        }
    }
    
    public void swap(char[] arr,int i,int j){
        char tmp = arr[i];
        arr[i] = arr[j];
        arr[j] = tmp; 
    }
}

 

posted on 2020-06-07 20:35  MoonBeautiful  阅读(187)  评论(0编辑  收藏  举报