看到网上有一个不过的算法:
/**
* @param eleStr -
* 待分配字符组成的串
* @param rstStr -
* 已分配字符组成的串
*/
public void depthSearch(String eleStr, String rstStr) {
if (eleStr.length() == 0) {
count++;
System.out.println(rstStr);
return;
}
for (int i = 0; i < eleStr.length(); i++) {
String currEle = eleStr.substring(i, i + 1); // 取出当前位的值
if (rstStr.length() == 2 && "4".equals(currEle))
continue; // 剪掉第三位为4的分支
if (rstStr.endsWith("3") && "5".equals(currEle))
continue; // 剪掉"35"相连的分支
if (rstStr.endsWith("5") && "3".equals(currEle))
continue; // 剪掉"53"相连的分支
if(eleStr.substring(0, i).indexOf(currEle) != -1)
continue; // 剪掉同一位上字符重复的分支(此题即剪掉重复的2)
depthSearch(eleStr.substring(0, i) + eleStr.substring(i + 1),
rstStr + currEle); // 用剩余的合法串继续递归
}
}
其中要处以的地方就是:eleStr.substring(0, i).indexOf(currEle) != -1
这个是去除重复的。即在一次循环中,在同一个位置上,如果这个数字已经出现过,
那就continue。比如有输入的:2365837,现在循环到后面的3的位置了,显然对于同一层的for循环是在一个位置上(第一次调用for循环,则该次循环的数字全都是在第一个位置),这样在这个for循环中已经出现过了3(意思就是这个位置上已经考虑过3了),所以在同一层循环上如果再有3,这是就要退出。
import java.util.Set; import java.util.TreeSet; public class MyTest { public static Set<String> set = new TreeSet<String>(); public static void perm(char[] n, int beg, int end) { if (beg == end) { addNumber(String.valueOf(n)); } else { for (int i = beg; i <= end; ++i) { swap(n, beg, i); perm(n, beg + 1, end); swap(n, beg, i); } } } public static void swap(char[] n, int x, int y) { if (x == y || n[x] == n[y]) { return; } char temp = n[x]; n[x] = n[y]; n[y] = temp; } public static void addNumber(String str) { if (str.charAt(2) == '4' || str.contains("35") || str.contains("53")) { return; } set.add(str); } public static void main(String args[]) { char[] number = new char[] { '1', '2', '2', '3', '4', '5' }; perm(number, 0, number.length - 1); System.out.println(set.size()); int cols = 10; for (String s : set) { System.out.print(s + " "); if (cols-- == 1) { System.out.println(); cols = 10; } } }
package com.sw.suanfa.first.ten;
import java.util.ArrayList;
import java.util.List;
/**
* 用java语言实现,一个组数:122345这6个数,打印出它所有可能的组合;要求4不能在第3位,3和5不能相连。
* 我的做法:首先,我确定用递归实现。
* 其次,不排除任何条件,打出所有的组合。
* 在递归中增加了preNum,和level参数,可方便的对条件【4不能在第3位,3和5不能相连】进行过滤。
* 在递归正增加了intList,便于排除重复。比如122345这个串中有2个2.则按照以上的算法会出现重复的情况。
* 这里用了一个intList主要是利用其方法indexOf,实际也可以通过数组循环的方式来查找,这里为了方便就用了list。
*
* @author songwei
* @date 2010.3.24
*
*/
public class ComposeArray {
public static void main(String[] args) {
int len = 6;
int[] numArray = {1,2,2,3,4,5};
int[] currentArray = new int[len];
getNextNumber(0,1,numArray,currentArray);
}
/**
*
* @param preNum 前一个数值
* @param level 当前层数
* @param numArray 当前层中能够选择的数值集合
* @param currentArray 正在操作的数组,当这个数组中的所有值均覆值后,则为条件允许情况下的一个数值集合。
*/
private static void getNextNumber(int preNum,int level,int[] numArray,int[] currentArray){
List<Integer> intList = new ArrayList<Integer>();
for(int i=0;i<numArray.length;i++){
int currentNum = numArray[i];
if(intList.indexOf(Integer.valueOf(currentNum))>-1) continue ;
intList.add(currentNum);
//4不能在第3位出现
if(level == 3 && currentNum == 4) continue ;
if(level != 1){
//3和5不能相连
if((currentNum ==5 && preNum == 3) || (currentNum ==3 && preNum == 5)){
continue ;
}
}
currentArray[level-1] = currentNum ;
int nextLevel = level +1 ;
if(level == currentArray.length){
OutArray(currentArray);
return ;
}else{
getNextNumber(currentNum,nextLevel,createNewArray(numArray,i),currentArray);
}
}
}
/**
* 创建一个新的数组,这个数组为该次排列中,下一个level可以出现的数值集合。
* @param oldArray
* @param orderNumber
* @return
*/
private static int[] createNewArray(int[] oldArray,int orderNumber){
if(oldArray.length<=1) return null ;
int newLen = oldArray.length-1 ;
int[] newArray =new int[newLen];
int newOrderNumber = 0 ;
for(int i=0;i<oldArray.length;i++){
if(i == orderNumber) continue ;
newArray[newOrderNumber] = oldArray[i];
newOrderNumber ++ ;
}
return newArray;
}
private static void OutArray(int[] array){
for(int i=0;i<array.length;i++){
System.out.print(array[i]);
}
System.out.println("");
}
}