我们应该牢记排列组合的数学公式,以便检验代码的输出是否正确。
在这里我把问题变化一下,可以得到3类问题:
public static void subtitution(char[] s, int start, int end) { if (start == end) { System.out.println(Arrays.toString(s)); } else { for (int i = start; i <= end; i++) { char temp; temp = s[start]; s[start] = s[i]; s[i] = temp; subtitution(s, start + 1, end); temp = s[i]; s[i] = s[start]; s[start] = temp; } } }
从置换这个名字我们可以得到一些灵感:就是从数组的第一个元素开始,和后面的元素依次交换。
[A, B, C, D] -- 1,首先是A和自己交换 2,后面的元素递归调用 3,将之前交换后产生的数组复原
最后输出的结果应该是n的阶乘。如上例为4*3*2*1=24种。大家每次做这种题时,应使用数学公式验证结果是否正确。
组合的数学公式是. 下面算法用数学公式检验是正确的。
import java.util.Stack; public class App { public static void main(String[] args) { comb(new String[]{"A", "B", "C", "D", "E", "F", "G"}, 3); } public static void comb(String[] m, int n) { Stack<String> buf = new Stack<String>(); doComb(m, 0, n, buf); } public static void doComb(String[] m, int start, int n, Stack<String> buf) { if (m.length - start + buf.size() == n) { for(String s : buf) { System.out.print(s + ","); } for(int i = start; i < m.length; ++i) { System.out.print(m[i] + ","); } System.out.println(""); }else if (start < m.length){ buf.push(m[start]); doComb(m, start + 1, n, buf); buf.pop(); doComb(m, start + 1, n, buf); } } }
现在我们就可以把问题分成两部分了:首先使用上面的方法二在m个字母中选择出n个,然后是用方法一对每种组合进行全排列就可以了。
import java.util.ArrayList; import java.util.Stack; public class App { public static ArrayList<String> al = new ArrayList<String>(); public static void main(String[] args) { comb(new String[] { "A", "B", "C", "D" }, 3); } public static void comb(String[] m, int n) { Stack<String> buf = new Stack<String>(); ArrayList<String> al = new ArrayList<String>(); al = doComb(m, 0, n, buf); for (String s : al) { perm(s.toCharArray(),0,2); } } public static ArrayList<String> doComb(String[] m, int start, int n, Stack<String> buf) { if (m.length - start + buf.size() == n) { String x = ""; for (String s : buf) { x = x + s; } for (int i = start; i < m.length; ++i) { x = x + m[i]; } al.add(x); } else if (start < m.length) { buf.push(m[start]); doComb(m, start + 1, n, buf); buf.pop(); doComb(m, start + 1, n, buf); } return al; } public static void perm(char[] buf, int start, int end){ if(start==end){ for(int i=0;i<=end;i++){ System.out.print(buf[i]); } System.out.println(); } else{ for(int i=start;i<=end;i++){ char temp=buf[start]; buf[start]=buf[i]; buf[i]=temp; perm(buf,start+1,end); temp=buf[start]; buf[start]=buf[i]; buf[i]=temp; } } } }
最后,如果仅需要计算有多少种可能的组合,而不需要打印,那么不论是置换,排列还是组合都很简单。我们可以直接使用数学公式计算(公式参考本文开始提到的另外一篇blog),也可以使用递归(递归解法可以参考另外一篇文章:http://blog.csdn.net/onlyqi/article/details/7536150)
下面是用递归计算组合的代码。
public class Testing { public static void main(String arg[]){ System.out.println(selector1(5,3)); } public static int selector1(int i, int j){ if(j == 1){ return i; } if(i == j){ return 1; } return selector1(i-1,j-1)+selector1(i-1,j); } }
<pre>