一、什么是全排列
百科:从n个不同元素中任取m(m≤n)个元素,按照一定的顺序排列起来,叫做从n个不同元素中取出m个元素的一个排列。当m=n时所有的排列情况叫全排列。
简单来说:一个字符串里面所有字符的排列情况叫做全排列。
二、全排列----循环执行
因为是所有字符的排列情况,所以要对字符串的每一个字符进行访问,并将找到在当前字符串情况所有可以插入的位置,然后保存返回,插入下一个字符时在此基础上继续操作,直到最后一个字符找到了所有可插入的位置。整个遍历结束,此时集合里面保存了所有的每个字符的排列方式,体现为:集合里面有字符串的每个字符随机排列的新字符串,且是所有可能的排列情况。
初始化一个集合res用来保存所有遍历字符串的情况,并最终返回该集合,初始化时保存第一个字符,因为第一个字符的可插入的位置只有一个。
第一层循环,遍历对象是字符串里面从索引1位置开始到结束的所有字符:
获取当前索引处的字符(从字符串的第二个字符开始,索引1位置),初始化第二个集合new_res,用来临时保存当前所有的字符串排列的情况。
第二层循环,遍历对象是res,res保存了上一个字符插入后的所有排列情况。在此res上的每一种情况插入下一个字符。
1.我们在插入第2个字符时就会有两个位置(例如:在字符串“a”中插入b,有ba、ab两种情况),一个在“前面插入”,一个在“后面插入”。每次插入后把当前字符串排列情况保存至new_res。
2.插入第2(至最后1个)字符,会出现可以在“中间插入”的情况。第三层循环,遍历对象是当前需要插入的字符串排列情况的位置索引,因为字符串排列情况的头尾在上一步已经完成,此时是从索引1位置插入至索引 length()-1位置。插入方式:substring()截取字符串+要插入的字符+substring()剩余子串。此方式就找到了当前字符串排列情况在“中间插入”的所有情况。
完成了第二层循环表示,截止到当前字符所有的字符串排列情况都已临时保存至new_res,之后返回给res。开始下一个字符的插入方式,,此时第二次循环遍历对象res已经有了截止到上一个字符所有的字符串排列情况。初始化new_res用来保存新一轮在插入当前字符后的所有排列情况。遍历res里的每一个字符串排列情况,进行插入操作,并临时保存至new_res。完成后再返回给res,直到最后一个字符结束,对整个字符串里的所有字符遍历结束,返回所有字符串中所有字符排列情况的集合。
三、全排列遍历代码
public static ArrayList<String> getAllPermutation(String s ) {
ArrayList<String> res = new ArrayList<>();
res.add(s.charAt(0) + ""); //初始化,包含第一个字符
//全排列的所有情况是访问字符串所有的字符并放在所有可能的位置上
//最外层循环是遍历整个字符串所有的字符
for (int i = 1; i < s.length(); i++) {
//临时保存当前所有情况的集合,最后返回给res,开始下一轮所有情况的插入操作
ArrayList<String> new_res = new ArrayList<>();
char c = s.charAt(i);//新字符
for (String str : res) {//访问上一趟集合中的每一种情况的字符串
//插入到每个字符串的每个位置,形成新的字符串
String newStr = c + str; //插在前面
new_res.add(newStr);//保存新的字符串情况,最后返回给res
newStr = str + c; //插在后面
new_res.add(newStr);
for (int j = 1; j < str.length(); j++) {//插在中间
newStr = str.substring(0, j) + c + str.substring(j);
new_res.add(newStr);
}
}
res = new_res;
}
return res;
}
四、总结
嵌套了三层循环,第一层是遍历所有字符串的字符,第二层是遍历截止到上一轮所有字符的排列情况,当前字符在每一个排列情况的进行所有情况的插入操作,第三层循环,对中间插入的情况进行遍历。
用了两个集合一个用来保存返回,另一个临时保存当前字符轮次的所有情况。
话很啰嗦,仅做个人学习总结使用,此方式暴力计算,不为最佳方式处理方式,却最好理解!!!