字符串全排列笔记

剑指offer 字符串全排列

描述

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

思路

> 这里参考了 https://www.nowcoder.com/questionTerminal/fe6b651b66ae47d7acce78ffdd9a96c7
  1. 如果无重复,固定第一个字符,递归取得首位后面的各种字符串组合,递归的出口,就是只剩一个字符的时候,递归的循环过程,就是从每个子串的第二个字符开始依次与第一个字符交换,然后继续处理子串。
  2. 如果有重复,由于全排列就是从第一个数字起,每个数分别与它后面的数字交换。

我们先尝试加个这样的判断(错误)——如果一个数与后面的数字相同那么这两个数就不交换了。例如abb,第一个数与后面两个数交换得bab,bba。但是abb中第二个数和第三个数相同,就不用交换了。

上面假设不成立的原因:如上,得到bab,bba。对于bab,第二个数和第三个数不同,则需要交换,得到bba,这里的bba和开始第一个数与第三个数交换的结果相同了。

因此,换个思维:对abb,第一个数a与第二个数b交换得到bab,然后考虑第一个数与第三个数交换,此时由于第三个数等于第二个数,所以第一个数就不再用与第三个数交换了。再考虑bab,它的第二个数与第三个数交换可以解决bba。此时全排列生成完毕!


import java.util.*;
public class Solution {
    public ArrayList<String> Permutation(String str) {
       ArrayList<String> list = new ArrayList<String>();
       if(str!=null && str.length()>0){
           Permuation(str.toCharArray(),0,list);
           Collections.sort(list);
       }
        return list;
    }

    private void Permuation(char[] chars,int i,ArrayList<String> list){
        if(i==chars.length-1){  //递归出口
            list.add(String.valueOf(chars));
        }else {
            Set<Character> charSet = new HashSet<Character>(); //判断重复字符
            for(int j=i;j<chars.length;++j){  // 第一个与后面的不重复的字符换位,然后递归。(注意这里是++j)
                    if(j==i || !charSet.contains(chars[j])){ //i=j 或者 set中没有这个字符(既不重复的字符)
                        charSet.add(chars[j]);//既前面的字符和后面的交换,如果重复了 就只交换一次!
                        swap(chars,i,j);
                        Permuation(chars,i+1,list);// i+1 下一次递归固定前面的字符
                        swap(chars,j,i);
            }
        }
    }
}

    private void swap(char[] cs,int i,int j){
        char temp = cs[i];
        cs[i] = cs[j];
        cs[j] = temp;
    }
}

猜你喜欢

转载自blog.csdn.net/xuezhan123/article/details/79633511