字符串排列
题目
输入一个字符串,按字典序打印出该字符串中字符的所有排列。例如输入字符串abc,则打印出由字符a,b,c所能排列出来的所有字符串abc,acb,bac,bca,cab和cba。
思路
我们求整个字符串的排列,可以看成两步:首先求所有可能出现在第一个位置的字符,即把第一个字符和后面所有的字符交换。如下图所示:
上图就是分别把第一个字符a和后面的b、c等字符交换的情形。首先固定第一个字符,求后面所有字符的排列。这个时候我们仍把后面的所有字符分为两部分:后面的字符的第一个字符,以及这个字符之后的所有字符。然后把第一个字符逐一和它后面的字符交换。
这道题和全排列不一样的地方是全排列1是没有重复全排列,全排列2是有重复但是不要全排列。这道题是没有说,默认是全排列1可以做。
代码一 剑指offer从第一个往后递推
public class Test4 {
public static void main(String[] args) {
permutation("abca".toCharArray());
}
public static void permutation(char[] chars) {
// 输入较验
if (chars == null || chars.length < 1) {
return;
}
// 进行排列操作
permutation(chars, 0);
}
public static void permutation(char[] chars, int begin) {
// 如果是最后一个元素了,就输出排列结果
if (chars.length - 1 == begin) {
System.out.print(new String(chars) + " ");
} else {
char tmp;
// 对当前还未处理的字符串进行处理,每个字符都可以作为当前处理位置的元素
for (int i = begin; i < chars.length; i++) {
// 下面是交换元素的位置
tmp = chars[begin];
chars[begin] = chars[i];
chars[i] = tmp;
// 处理下一个位置
permutation(chars, begin + 1);
}
}
}
代码二 dfs
public class Test5 {
public static void main(String[] args) {
List<String> strings = Permutation("abc");
for(String str : strings){
System.out.println(str);
}
}
static ArrayList<String> returnList = new ArrayList<>();
public static List<String> Permutation(String str) {
if(str=="" || str.length() ==0){
return returnList;
}
helper(str.toCharArray(),0);
Collections.sort(returnList);
return returnList;
}
public static void helper(char[] chars, int index) {
if(index == chars.length-1){
String val = String.valueOf(chars);
if (!returnList.contains(val)) {
//如果最后list没有这个string,因为可能交换后有重复的
returnList.add(val);
}
return;
}
for(int i =index;i<chars.length;i++){
swap(chars, index, i);
helper(chars,index+1);
swap(chars, index, i);
}
}
public static void swap(char[] chars,int i, int j) {//交换数组中的两个位置中的值
char temp =chars[i];
chars[i] = chars[j];
chars[j] = temp;
}
}
代码三 全排列代码
public static void main(String[] args) {
List<List<Character>> returnlist = permute("abc".toCharArray());
for(int i =0;i<returnlist.size();i++){
System.out.println(returnlist.get(i));
}
}
static List<List<Character>> list = new ArrayList<>();
public static List<List<Character>> permute(char[] nums) {
if (nums == null || nums.length == 0) {
return list;
}
List<Character> list1 = new ArrayList<>();
dpf(nums,list1);
return list;
}
public static void dpf(char[] nums,List<Character> list1){
if(list1.size() ==nums.length){
list.add(new ArrayList<>(list1));
}else {
for(int i =0;i<nums.length;i++){
//如果已经在数组里面了
if(list1.contains(nums[i])){
continue;
}
list1.add(nums[i]);
dpf(nums,list1);
list1.remove(list1.size()-1);
}
}
}
代码四 大神解读
/**
* 题目:
* 字符串的排列 -- newcoder 剑指Offer 27
*
* 题目描述:
* 输入一个字符串,按字典序打印出该字符串中字符的所有排列。
* 例如输入字符串abc,则打印出由字符a,b,c 所能排列出来的所有字符串
* abc,acb,bac,bca,cab和cba。
*
* 输入描述:
* 输入一个字符串,长度不超过9(可能有字符重复),字符只包括大小写字母。
*/
public class Permutation
{
/**
* 思路:
*
* 对于无重复值的情况
*
* 固定第一个字符,递归取得首位后面的各种字符串组合;
* 再把第一个字符与后面每一个字符交换,并同样递归获得首位后面的字符串组合; *递归的出口,就是只剩一个字符的时候,
* 递归的循环过程,就是从每个子串的第二个字符开始依次与第一个字符交换,然后继续处理子串。
*
* 假如有重复值呢?
* 由于全排列就是从第一个数字起,每个数分别与它后面的数字交换,我们先尝试加个这样的判断——如果一个数与后面的数字相同那么这两个数就不交换了。
* 例如abb,第一个数与后面两个数交换得bab,bba。然后abb中第二个数和第三个数相同,就不用交换了。
* 但是对bab,第二个数和第三个数不 同,则需要交换,得到bba。
* 由于这里的bba和开始第一个数与第三个数交换的结果相同了,因此这个方法不行。
*
* 换种思维,对abb,第一个数a与第二个数b交换得到bab,然后考虑第一个数与第三个数交换,此时由于第三个数等于第二个数,
* 所以第一个数就不再用与第三个数交换了。再考虑bab,它的第二个数与第三个数交换可以解决bba。此时全排列生成完毕!
*
*/
public ArrayList<String> permutation(String str) {
ArrayList<String> ret = new ArrayList<>();
if (str == null || str.isEmpty()) {
return ret;
}
char[] arr = str.toCharArray();
permutation(arr, 0, ret);
Collections.sort(ret);
return ret;
}
private void permutation(char[] arr, int begin, ArrayList<String> cache) {
if (begin == arr.length - 1) {
cache.add(new String(arr));
return;
}
int len = arr.length;
for (int i=begin; i<len; i++) {
// 与begin不同位置的元素相等,不需要交换
if (i!=begin && arr[i]==arr[begin]) {
continue;
}
// 交换元素
swap(arr, begin, i);
// 处理后续元素
permutation(arr, begin+1, cache);
// 数组复原
swap(arr, begin, i);
}
}
private void swap(char[] arr, int i, int j) {
if (i == j) {
return;
}
arr[i] = (char)(arr[i]^arr[j]);
arr[j] = (char)(arr[i]^arr[j]);
arr[i] = (char)(arr[i]^arr[j]);
}