标签:sub ace ffd hashset 需要 字典序 输入 大于 swa
输入一个字符串,长度不超过9(可能有字符重复),字符只包括大小写字母。
题目链接:
分析:
第一个字符固定,子问题,从第二个字符起后面全排列……一直到只有一个字符。
第一个字符与第二个字符交换,子问题,从第二个字符起后面全排列……一直到只有一个字符。
……
存在重复字符问题:
* *由于全排列就是从第一个数字起,每个数分别与它后面的数字交换,我们先尝试加个这样的判断——如果一个数与后面的数字相同那么这两个数就不交换了。
* 例如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; } }
标签:sub ace ffd hashset 需要 字典序 输入 大于 swa
原文地址:https://www.cnblogs.com/MoonBeautiful/p/13062113.html