您的位置:首页 > 职场人生

字符串的排列与组合

2016-05-28 17:18 471 查看

字符串全排列

求字符串的排列可以把字符串看成两部分:第一部分为它的第一个字符,第二部分是后面的所有字符。
求字符串的全排列的时候,可以用两步完成:首先求所有可能出现在第一个位置的字符,即把第一个字符与后面的所有字符交换。第二步固定第一个字符,求后面所有字符的排列。从中可以看出是典型的递归思路。 
/**
* 字符串的全排列
*/
public class Permutation {

@Test
public void testCase() {
permutation("abcc");
}

/**
* 求字符串的全排列
*
* @param str
*/
public void permutation(String str) {
permutation(str.toCharArray(), 0);
}

/**
* 求begin位置开始字符数组的排列
*
* @param strArr 字符数组
* @param begin  begin位置
*/
private void permutation(char[] strArr, int begin) {
if (begin == strArr.length - 1) {//begin等于最后一个字符位置结束递归
System.out.println(Arrays.toString(strArr));
} else {
for (int i = begin; i < strArr.length; i++) {
//1.把第一个字符与后边的所有字符交换
swap(strArr, begin, i);
//2.固定第一个字符,对后边的所有字符全排列
permutation(strArr, begin + 1);
//3.把交换到后边的字符交换回来
swap(strArr, begin, i);
}
}
}

/**
* 交换数组中k1与k2位置的两个元素
*
* @param arr
* @param k1
* @param k2
*/
private void swap(char[] arr, int k1, int k2) {
char temp = arr[k1];
arr[k1] = arr[k2];
arr[k2] = temp;
}
}


上述的代码在字符不重复的情况下是正常的,如果出现重复字符例如"abcc",就会输出重复的排列情况。可以通过判断当前准备交换的字符,在begin字符前面的子字符串中是否出现过了,若出现了,就不交换,若没出现就交换。修改下上述方法。

/**
* 字符串的全排列
*/
public class Permutation {

@Test
public void testCase() {
permutation("abcc");
}

/**
* 求字符串的全排列
*
* @param str
*/
public void permutation(String str) {
permutation(str.toCharArray(), 0);
}

/**
* 求begin位置开始字符数组的排列
*
* @param strArr 字符数组
* @param begin  begin位置
*/
private void permutation(char[] strArr, int begin) {
if (begin == strArr.length - 1) {//begin等于最后一个字符位置结束递归
System.out.println(Arrays.toString(strArr));
} else {
for (int i = begin; i < strArr.length; i++) {
if (!isExist(strArr, begin, i)) {
//1.把第一个字符与后边的所有字符交换
swap(strArr, begin, i);
//2.固定第一个字符,对后边的所有字符全排列
permutation(strArr, begin + 1);
//3.把交换到后边的字符交换回来
swap(strArr, begin, i);
}
}
}
}

/**
* isExist判断j位置的字符是否已经在list[0]~list[j-1]中出现过了
* list是含重复字符的数组,i是指示当前位置的游标,j是要判断的字符的位置
*/
public boolean isExist(char[] arr, int i, int j) {
for (int k = i; k < j; k++) {
if (arr[j] == arr[k]) {
return true;
}
}
return false;
}

/**
* 交换数组中k1与k2位置的两个元素
*
* @param arr
* @param k1
* @param k2
*/
private void swap(char[] arr, int k1, int k2) {
char temp = arr[k1];
arr[k1] = arr[k2];
arr[k2] = temp;
}
}

字符串组合

求n个字符中m个字符的组合的时候,可以把这n个字符分成两部分:第一个字符和其余的所有字符。如果组合里包含第一个字符,则下一步在剩余的字符里选取m-1个字符;如果组合里不包含第一个字符,则下一步在剩余的n-1个字符里选取m个字符,从中可以看出又是个递归的过程。

/**
* 求字符串的组合
*/
public class Combination {

@Test
public void testCase() {
combination("abc");
}

/**
* 打印输入字符串包含的所有字符的所有组合
*
* @param str
*/
public void combination(String str) {
char[] arr = str.toCharArray();
for (int i = 1; i <= arr.length; i++) {
combination(arr, 0, i);
}
}

/**
* 存储组合的容器
*/
private Stack<Character> stack = new Stack<>();

/**
* 从begin位置开始,选取num个字符
*
* @param strArr
* @param begin
* @param num
*/
private void combination(char[] strArr, int begin, int num) {
if (num == 0) {
System.out.println(stack);
return;
}
if (begin >= strArr.length) {
return;
} else {
//把第一个字符放入组合中,在剩余的字符中选取num-1个字符
stack.push(strArr[begin]);
combination(strArr, begin + 1, num - 1);
//组合里不包含第一个字符,则下一步在剩余的字符中选取num个字符
stack.pop();
combination(strArr, begin + 1, num);
}
}
}

1、八皇后问题:在8*8的国际象棋上摆放八个皇后,使其任意两个皇后不能在同一行,同一列或者同一对角线上,求符合的摆法。
2、把8个数字分别放到正方体的8个顶点上,使正方体三组相对面上的四个定点的和都相等
上述两个问题都可以使8个数字全排列,分别进行判断是否符合上述条件 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息