找到字符串的所有排列的优雅方法是什么.是的ba,会是ba和ab,但是怎么样abcdefgh?是否有任何Java实现示例?
小智 585
public static void permutation(String str) {
permutation("", str);
}
private static void permutation(String prefix, String str) {
int n = str.length();
if (n == 0) System.out.println(prefix);
else {
for (int i = 0; i < n; i++)
permutation(prefix + str.charAt(i), str.substring(0, i) + str.substring(i+1, n));
}
}
Run Code Online (Sandbox Code Playgroud)
(通过Java编程简介)
Mar*_*ers 194
使用递归.
jea*_*mex 67
这是我的解决方案,它基于"破解编码面试"一书的想法(P54):
/**
* List permutations of a string.
*
* @param s the input string
* @return the list of permutations
*/
public static ArrayList<String> permutation(String s) {
// The result
ArrayList<String> res = new ArrayList<String>();
// If input string's length is 1, return {s}
if (s.length() == 1) {
res.add(s);
} else if (s.length() > 1) {
int lastIndex = s.length() - 1;
// Find out the last character
String last = s.substring(lastIndex);
// Rest of the string
String rest = s.substring(0, lastIndex);
// Perform permutation on the rest string and
// merge with the last character
res = merge(permutation(rest), last);
}
return res;
}
/**
* @param list a result of permutation, e.g. {"ab", "ba"}
* @param c the last character
* @return a merged new list, e.g. {"cab", "acb" ... }
*/
public static ArrayList<String> merge(ArrayList<String> list, String c) {
ArrayList<String> res = new ArrayList<>();
// Loop through all the string in the list
for (String s : list) {
// For each string, insert the last character to all possible positions
// and add them to the new list
for (int i = 0; i <= s.length(); ++i) {
String ps = new StringBuffer(s).insert(i, c).toString();
res.add(ps);
}
}
return res;
}
Run Code Online (Sandbox Code Playgroud)
运行字符串"abcd"的输出:
第1步:合并[a]和b:[ba,ab]
第2步:合并[ba,ab]和c:[cba,bca,bac,cab,acb,abc]
第3步:合并[cba,bca,bac,cab,acb,abc]和d:[dcba,cdba,cbda,cbad,dbca,bdca,bcda,bcad,dbac,bdac,badc,bacd,dcab,cdab,cadb ,cabd,dacb,adcb,acdb,acbd,dabc,adbc,abdc,abcd]
sri*_*dla 51
在这里和其他论坛给出的所有解决方案中,我最喜欢Mark Byers.这个描述实际上让我自己思考和编码.太糟糕了,因为我是新手,我无法对他的解决方案进行投票.
无论如何,这是我对他的描述的实现
public class PermTest {
public static void main(String[] args) throws Exception {
String str = "abcdef";
StringBuffer strBuf = new StringBuffer(str);
doPerm(strBuf,0);
}
private static void doPerm(StringBuffer str, int index){
if(index == str.length())
System.out.println(str);
else { //recursively solve this by placing all other chars at current first pos
doPerm(str, index+1);
for (int i = index+1; i < str.length(); i++) {//start swapping all other chars with current first char
swap(str,index, i);
doPerm(str, index+1);
swap(str,i, index);//restore back my string buffer
}
}
}
private static void swap(StringBuffer str, int pos1, int pos2){
char t1 = str.charAt(pos1);
str.setCharAt(pos1, str.charAt(pos2));
str.setCharAt(pos2, t1);
}
}
Run Code Online (Sandbox Code Playgroud)
我更倾向于在此线程中的第一个解决方案之前使用此解决方案,因为此解决方案使用StringBuffer.我不会说我的解决方案不会创建任何临时字符串(它实际上在调用StringBuffer的system.out.println地方toString()).但我觉得这比创建太多字符串文字的第一个解决方案更好.可能是一些有性能的人可以在"记忆"方面评估这个(因为'时间'它已经因为额外的'交换'而滞后)
小智 20
Java中一个非常基本的解决方案是,如果要存储和返回解决方案字符串,请使用递归+设置(以避免重复):
public static Set<String> generatePerm(String input)
{
Set<String> set = new HashSet<String>();
if (input == "")
return set;
Character a = input.charAt(0);
if (input.length() > 1)
{
input = input.substring(1);
Set<String> permSet = generatePerm(input);
for (String x : permSet)
{
for (int i = 0; i <= x.length(); i++)
{
set.add(x.substring(0, i) + a + x.substring(i));
}
}
}
else
{
set.add(a + "");
}
return set;
}
Run Code Online (Sandbox Code Playgroud)
gre*_*pit 15
所有以前的贡献者都做了很好的解释和提供代码.我认为我也应该分享这种方法,因为它也可以帮助别人.解决方案基于(堆积算法)
几件事:
请注意,excel中描述的最后一项仅用于帮助您更好地可视化逻辑.因此,最后一列中的实际值将是2,1,0(如果我们要运行代码,因为我们正在处理数组,数组以0开头).
交换算法基于当前位置的偶数或奇数值发生.如果你看一下调用swap方法的位置,这是非常自我解释的.你可以看到发生了什么.
这是发生的事情:

public static void main(String[] args) {
String ourword = "abc";
String[] ourArray = ourword.split("");
permute(ourArray, ourArray.length);
}
private static void swap(String[] ourarray, int right, int left) {
String temp = ourarray[right];
ourarray[right] = ourarray[left];
ourarray[left] = temp;
}
public static void permute(String[] ourArray, int currentPosition) {
if (currentPosition == 1) {
System.out.println(Arrays.toString(ourArray));
} else {
for (int i = 0; i < currentPosition; i++) {
// subtract one from the last position (here is where you are
// selecting the the next last item
permute(ourArray, currentPosition - 1);
// if it's odd position
if (currentPosition % 2 == 1) {
swap(ourArray, 0, currentPosition - 1);
} else {
swap(ourArray, i, currentPosition - 1);
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
小智 11
这个没有递归
public static void permute(String s) {
if(null==s || s.isEmpty()) {
return;
}
// List containing words formed in each iteration
List<String> strings = new LinkedList<String>();
strings.add(String.valueOf(s.charAt(0))); // add the first element to the list
// Temp list that holds the set of strings for
// appending the current character to all position in each word in the original list
List<String> tempList = new LinkedList<String>();
for(int i=1; i< s.length(); i++) {
for(int j=0; j<strings.size(); j++) {
tempList.addAll(merge(s.charAt(i), strings.get(j)));
}
strings.removeAll(strings);
strings.addAll(tempList);
tempList.removeAll(tempList);
}
for(int i=0; i<strings.size(); i++) {
System.out.println(strings.get(i));
}
}
/**
* helper method that appends the given character at each position in the given string
* and returns a set of such modified strings
* - set removes duplicates if any(in case a character is repeated)
*/
private static Set<String> merge(Character c, String s) {
if(s==null || s.isEmpty()) {
return null;
}
int len = s.length();
StringBuilder sb = new StringBuilder();
Set<String> list = new HashSet<String>();
for(int i=0; i<= len; i++) {
sb = new StringBuilder();
sb.append(s.substring(0, i) + c + s.substring(i, len));
list.add(sb.toString());
}
return list;
}
Run Code Online (Sandbox Code Playgroud)
Vih*_*rma 10
我们以输入abc为例.
从cset(["c"])中的最后一个元素()开始,然后将第二个最后一个元素(b)添加到它的正面,结尾和中间的每个可能位置["bc", "cb"],然后以相同的方式添加下一个元素从back(a)到集合中的每个字符串:
"a" + "bc" = ["abc", "bac", "bca"] and "a" + "cb" = ["acb" ,"cab", "cba"]
Run Code Online (Sandbox Code Playgroud)
因此整个排列:
["abc", "bac", "bca","acb" ,"cab", "cba"]
Run Code Online (Sandbox Code Playgroud)
码:
public class Test
{
static Set<String> permutations;
static Set<String> result = new HashSet<String>();
public static Set<String> permutation(String string) {
permutations = new HashSet<String>();
int n = string.length();
for (int i = n - 1; i >= 0; i--)
{
shuffle(string.charAt(i));
}
return permutations;
}
private static void shuffle(char c) {
if (permutations.size() == 0) {
permutations.add(String.valueOf(c));
} else {
Iterator<String> it = permutations.iterator();
for (int i = 0; i < permutations.size(); i++) {
String temp1;
for (; it.hasNext();) {
temp1 = it.next();
for (int k = 0; k < temp1.length() + 1; k += 1) {
StringBuilder sb = new StringBuilder(temp1);
sb.insert(k, c);
result.add(sb.toString());
}
}
}
permutations = result;
//'result' has to be refreshed so that in next run it doesn't contain stale values.
result = new HashSet<String>();
}
}
public static void main(String[] args) {
Set<String> result = permutation("abc");
System.out.println("\nThere are total of " + result.size() + " permutations:");
Iterator<String> it = result.iterator();
while (it.hasNext()) {
System.out.println(it.next());
}
}
}
Run Code Online (Sandbox Code Playgroud)
那么这是一个优雅的,非递归的,O(n!)解决方案:
public static StringBuilder[] permutations(String s) {
if (s.length() == 0)
return null;
int length = fact(s.length());
StringBuilder[] sb = new StringBuilder[length];
for (int i = 0; i < length; i++) {
sb[i] = new StringBuilder();
}
for (int i = 0; i < s.length(); i++) {
char ch = s.charAt(i);
int times = length / (i + 1);
for (int j = 0; j < times; j++) {
for (int k = 0; k < length / times; k++) {
sb[j * length / times + k].insert(k, ch);
}
}
}
return sb;
}
Run Code Online (Sandbox Code Playgroud)
使用递归。
当输入是空字符串时,唯一的排列是空字符串。尝试将字符串中的每个字母作为第一个字母,然后使用递归调用找到其余字母的所有排列。
import java.util.ArrayList;
import java.util.List;
class Permutation {
private static List<String> permutation(String prefix, String str) {
List<String> permutations = new ArrayList<>();
int n = str.length();
if (n == 0) {
permutations.add(prefix);
} else {
for (int i = 0; i < n; i++) {
permutations.addAll(permutation(prefix + str.charAt(i), str.substring(i + 1, n) + str.substring(0, i)));
}
}
return permutations;
}
public static void main(String[] args) {
List<String> perms = permutation("", "abcd");
String[] array = new String[perms.size()];
for (int i = 0; i < perms.size(); i++) {
array[i] = perms.get(i);
}
int x = array.length;
for (final String anArray : array) {
System.out.println(anArray);
}
}
}
Run Code Online (Sandbox Code Playgroud)
小智 5
一个简单的解决方案可能是使用两个指针递归地交换字符.
public static void main(String[] args)
{
String str="abcdefgh";
perm(str);
}
public static void perm(String str)
{ char[] char_arr=str.toCharArray();
helper(char_arr,0);
}
public static void helper(char[] char_arr, int i)
{
if(i==char_arr.length-1)
{
// print the shuffled string
String str="";
for(int j=0; j<char_arr.length; j++)
{
str=str+char_arr[j];
}
System.out.println(str);
}
else
{
for(int j=i; j<char_arr.length; j++)
{
char tmp = char_arr[i];
char_arr[i] = char_arr[j];
char_arr[j] = tmp;
helper(char_arr,i+1);
char tmp1 = char_arr[i];
char_arr[i] = char_arr[j];
char_arr[j] = tmp1;
}
}
}
Run Code Online (Sandbox Code Playgroud)
python实现
def getPermutation(s, prefix=''):
if len(s) == 0:
print prefix
for i in range(len(s)):
getPermutation(s[0:i]+s[i+1:len(s)],prefix+s[i] )
getPermutation('abcd','')
Run Code Online (Sandbox Code Playgroud)
这是我通过对排列和递归函数调用的基本理解所做的。需要一点时间,但它是独立完成的。
public class LexicographicPermutations {
public static void main(String[] args) {
// TODO Auto-generated method stub
String s="abc";
List<String>combinations=new ArrayList<String>();
combinations=permutations(s);
Collections.sort(combinations);
System.out.println(combinations);
}
private static List<String> permutations(String s) {
// TODO Auto-generated method stub
List<String>combinations=new ArrayList<String>();
if(s.length()==1){
combinations.add(s);
}
else{
for(int i=0;i<s.length();i++){
List<String>temp=permutations(s.substring(0, i)+s.substring(i+1));
for (String string : temp) {
combinations.add(s.charAt(i)+string);
}
}
}
return combinations;
}}
Run Code Online (Sandbox Code Playgroud)
将输出生成为[abc, acb, bac, bca, cab, cba].
其背后的基本逻辑是
对于每个字符,将其视为第一个字符并找到剩余字符的组合。例如[abc](Combination of abc)->。
a->[bc](a x Combination of (bc))->{abc,acb}b->[ac](b x Combination of (ac))->{bac,bca}c->[ab](c x Combination of (ab))->{cab,cba}然后递归地调用每个[bc], [ac]&[ab]独立。