我总结了全排列的各种题解,若有不全之处还请各位大大们慷慨指出.
1. 全排列之取球游戏
问题描述:
m球中取n个球,共有多少种取法
解题思路:
用递归思想解题.乍眼一看貌似递归无下手之处,其实每一个球只有两种情况:要么取, 要么不取. 若用m表示球的个数,n表示需要取的球的总数,那么当前球取则return fun(m - 1, n - 1) ; 不取则 return fun(m - 1, n);
代码实现:
github上相关代码:https://github.com/striner/javaCode/blob/master/Take%20the%20ball
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
//全排列练习
//1.取球游戏 m球中取n个球,共有多少种取法
public class Main {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
int m = input.nextInt(); //共有m个球
int n = input.nextInt(); //取n个球
int num = fun(m, n); //共有num种取法
System.out.println(num);
input.close();
}
public static int fun(int m, int n) {
if (n == 0) return 1; //m个球中取0个球,只有一种取法
if (m == n) return 1; //m个球中取m个球,只有一种取法
//假设有一个球做了标记,那么它就有两种取法: 取 或 不取
return fun(m - 1, n - 1) + fun(m - 1, n);
}
}
运行结果:
2. 全排列之字符串数组组合计数问题
问题描述:
求出输入字符串数组的全排列结果
解题思路:
用ArrayList<>集合存放每一种可能的排列.用fun(str.substring(0, i) + str.substring(i + 1))递归,将每一次的str.charAt(i)提取出来并拼到下一次递归的排列结果之前.
代码实现:
github上相关代码:https://github.com/striner/javaCode/blob/master/An%20array%20of%20strings%20of%20Full%20Permutation
//2. 字符串数组全排列 组合计数问题
//求出输入字符串数组的全排列结果
class Main1 {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
String str = input.nextLine();
List<String> list = fun(str);
for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i));
}
input.close();
}
public static List<String> fun(String str) {
List<String> list = new ArrayList<>();
if (str.length() == 1) {
list.add(str);
return list;
}
for (int i = 0; i < str.length(); i++) {
char c = str.charAt(i);
List<String> t = fun(str.substring(0, i) + str.substring(i + 1));
for (int j = 0; j < t.size(); j++) {
list.add("" + c + t.get(j));
}
}
return list;
}
}
运行结果:
3.全排列之字符串数组组合计数问题(数组实现)
问题描述:
求出输入字符串数组的全排列结果
解题思路:
通过数组中每一个元素与其后面元素一一交换实现
代码实现:
//3. 用数组实现字符串数组的全排列
//通过数组中每一个元素与其后面元素一一交换实现
class Main2 {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
String str = input.nextLine();
char[] arr = str.toCharArray();
fun(arr, 0);
input.close();
}
public static void fun(char[] arr, int index) { //arr:待排数据 index: 考虑的当前位置(数组下标)
if (index == arr.length - 1) {
System.out.println(String.valueOf(arr));
return;
}
for (int i = index; i < arr.length; i++) {
char ch = arr[i]; arr[i] = arr[index]; arr[index] = ch; //试探
fun(arr, index + 1);
ch = arr[i]; arr[i] = arr[index]; arr[index] = ch; //回溯
}
}
}
运行结果:
4. 全排列之固定数目的组合问题
问题描述:
输入一串字符串数组,并中取3个数输出所有的可能结果
解题思路:
由于所需取出的球数仅为3种,可以直接暴力破解. 后文会介绍取出不定球数或球数很多时的解法.
代码实现:
github上相关代码:https://github.com/striner/javaCode/blob/master/The%20combinatorial%20problem%20of%20fixed%20number
//4. 固定数目的组合问题 组合枚举循环暴力法
//输入一串字符串数组,并中取3个数输出所有的可能结果
class Main3 {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
String string = input.nextLine();
char[] ch = string.toCharArray();
fun(ch);
input.close();
}
public static void fun(char[] ch) {
for (int i = 0; i < ch.length; i++) {
for (int j = i + 1; j < ch.length; j++) {
for (int k = j + 1; k < ch.length; k++) {
System.out.println("" + ch[i] + ch[j] + ch[k]);
}
}
}
}
}
运行结果:
5. 全排列之不定数目的组合问题
问题描述:
从输入的字符数组中取n个字母,都有哪些取法
解题思路:
采用组合枚举递归法解题,并用ArrayList对每种排列结果进行存储.
代码实现:
github上相关代码:https://github.com/striner/javaCode/blob/master/Variable%20number%20of%20combinatorial%20problems
//5. 不定数目的组合问题 组合枚举递归法
//从输入的字符数组中取n个字母,都有哪些取法
class Main4 {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
String str = input.next();
int n = input.nextInt(); //串str中取n个字母
List<String> list = fun(str, n);
for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i));
}
input.close();
}
public static List<String> fun(String str, int n) {
List<String> list = new ArrayList<>();
if (n == 0) {
list.add("");
return list;
}
for (int i = 0; i < str.length(); i++) {
char ch = str.charAt(i);
List<String> t = fun(str.substring(i + 1), n - 1);
for (int j = 0; j < t.size(); j++) {
list.add("" + ch + t.get(j));
}
}
return list;
}
}
运行结果:
6. 全排列之组合重复问题
问题描述:
"AABBBC" 取3个,都有哪些取法
解题思路:
此题用data[]数组对每个元素的最大个数进行存储,用x[]来表示每个元素所取的个数,采用递归方式求得每一种结果并打印输出.
代码实现:
github上相关代码:https://github.com/striner/javaCode/blob/master/Repeat%20combination
//6. 组合重复
//"AABBBC" 取3个,都有哪些取法
class Main5 {
public static void main(String[] args) {
int[] data = {2, 3, 1}; //每个元素的最大个数 限制条件
int[] x = new int[data.length]; //每个元素取几个
fun(data, x, 0, 3);
}
public static void fun(int[] data, int[] x, int k, int goal) { //k: 当前考虑的数的下标 goal:距离目标的剩余个数
if (k == x.length) {
if (goal == 0)
work(x);
return;
}
for (int i = 0; i <= Math.min(data[k], goal); i++) {
x[k] = i;
fun(data, x, k + 1, goal - i); //试探
}
x[k] = 0; //回溯
}
public static void work(int[] x) {
for (int i = 0; i < x.length; i++) {
for (int j = 0; j < x[i]; j++) { //x[i]表示第i项的数最高出现几次
System.out.print((char)('A' + i));
}
}
System.out.println();
}
}
运行结果: