Java 排列组合的有趣算法

1. 用1、2、3、4、5这五个数字,用java写一个main函数,打印出所有不同的排列,如:51234、41235等。 

Java代码  收藏代码
  1. public class TestQuestion {  
  2. static int[] bits = new int[] { 12345 };  
  3.   
  4. /** 
  5. * @param args 
  6. */  
  7. public static void main(String[] args) {  
  8. sort("", bits);  
  9. }  
  10.   
  11. private static void sort(String prefix, int[] a) {  
  12. if (a.length == 1) {  
  13. System.out.println(prefix + a[0]);  
  14. }  
  15.   
  16. for (int i = 0; i < a.length; i++) {  
  17. sort(prefix + a[i], copy(a, i));  
  18. }  
  19. }  
  20.   
  21. private static int[] copy(int[] a,int index){  
  22. int[] b = new int[a.length-1];  
  23. System.arraycopy(a, 0, b, 0, index);  
  24. System.arraycopy(a, index+1, b, index, a.length-index-1);  
  25. return b;  
  26. }  
  27. }  


2. 对第一题增加难度,用1、2、2、3、4、5这六个数字,用java写一个main函数,打印出所有不同的排列,如:512234、412345等,要求:"4"不能在第三位,"3"与"5"不能相连。 

基本思路: 
2-1. 把问题归结为图结构的遍历问题。图遍历思想:实际上6个数字就是六个结点,把六个结点连接成无向连通图,对于每一个结点求这个图形的遍历路径,所有结点的遍历路径就是最后对这6个数字的排列组合结果集。 

2-2. 显然这个结果集还未达到题目的要求。从以下几个方面考虑:                                                 

    2-2-1.   3,5不能相连:实际要求这个连通图的结点3,5之间不能连通, 可在构造图结构时就满足改条件,然后再遍历图。 
    2-2-2.   不能有重复: 考虑到有两个2,明显会存在重复结果,可以把结果集放在TreeSet中过滤重复结果 
    2-2-3.   4不能在第三位: 仍旧在结果集中去除满足此条件的结果。 

采用二维数组定义图结构,最后的代码是: 

Java代码  收藏代码
  1. import java.util.Iterator;  
  2. import java.util.TreeSet;  
  3.   
  4. public class TestQuestion {  
  5.   
  6. private String[] b = new String[]{"1""2""2""3""4""5"};  
  7. private int n = b.length;  
  8. private boolean[] visited = new boolean[n];  
  9. private int[][] a = new int[n][n];  
  10. private String result = "";  
  11. private TreeSet set = new TreeSet();  
  12.   
  13. public static void main(String[] args) {  
  14. new TestQuestion().start();  
  15. }  
  16.   
  17. private void start() {  
  18.   
  19. // Initial the map a[][]  
  20. for (int i = 0; i < n; i++) {  
  21. for (int j = 0; j < n; j++) {  
  22. if (i == j) {  
  23. a[i][j] = 0;  
  24. else {  
  25.     a[i][j] = 1;  
  26. }  
  27. }  
  28. }  
  29.   
  30. // 3 and 5 can not be the neighbor.  
  31. a[3][5] = 0;  
  32. a[5][3] = 0;  
  33.   
  34. // Begin to depth search.  
  35. for (int i = 0; i < n; i++) {  
  36.     this.depthFirstSearch(i);  
  37. }  
  38.   
  39. // Print result treeset.  
  40. Iterator it = set.iterator();  
  41. while (it.hasNext()) {  
  42. String string = (String) it.next();  
  43. // "4" can not be the third position.  
  44. if (string.indexOf("4") != 2) {  
  45. System.out.println(string);  
  46. }  
  47. }  
  48. }  
  49.   
  50. private void depthFirstSearch(int startIndex) {  
  51. visited[startIndex] = true;  
  52. result = result + b[startIndex];  
  53. if (result.length() == n) {  
  54. // Filt the duplicate value.  
  55. set.add(result);  
  56. }  
  57. for(int j = 0; j < n; j++) {  
  58. if (a[startIndex][j] == 1 && visited[j] == false) {  
  59. depthFirstSearch(j);  
  60. else {  
  61. continue;  
  62. }  
  63. }  
  64.   
  65. // restore the result value and visited value after listing a node.  
  66.     result = result.substring(0, result.length() -1);  
  67.     visited[startIndex] = false;  
  68. }  
  69. }  


3.   递归思想。递归要抓住的关键是:(1)递归出口;(2)地推逐步向出口逼近。 

3-1. 汉诺塔 

  这是递归的超经典的例子,几乎每本程序设计书上谈到递归都会介绍。具体情景不再赘述。以我上述的方法观之: 

    3-1-1. 递归的出口在于disk数为一的时候 

    3-1-2. 向出口逼近:如果不是一,是n ,则我们先挪动上面n-1块disk,等上面挪完,即递归返回的时候,我们挪动最底下的disk. 

  仅仅如此,一个貌似十分复杂的问题就解决了,因为挪动那n-1块disk的时候,会继续向上减少,直到disk的数量为一为止。下面给出代码: 

Java代码  收藏代码
  1. import javax.swing.JOptionPane;   
  2. public class Hanoi{   
  3. private static final String DISK_B = "diskB";   
  4. private static final String DISK_C = "diskC";   
  5. private static final String DISK_A = "diskA";   
  6. static String from=DISK_A;   
  7. static String to=DISK_C;   
  8. static String mid=DISK_B;   
  9. public static void main(String[] args) {   
  10. String input=JOptionPane.showInputDialog("please input the number of the disks you want me move.");   
  11. int num=Integer.parseInt(input);   
  12. move(num,from,mid,to);   
  13. }   
  14. private static void move(int num, String from2, String mid2, String to2) {   
  15. if(num==1){   
  16. System.out.println("move disk 1 from "+from2+" to "+to2);   
  17. }   
  18. else {   
  19. move(num-1,from2,to2,mid2);   
  20. System.out.println("move disk "+num+" from "+from2+" to "+to2);   
  21. move(num-1,mid2,from2,to2);   
  22. }   
  23. }   
  24. }  
3-2. 这是一个排列的例子,它所做的工作是将输入的一个字符串中的所有元素进行排序并输出,例如:你给出的参数是"abc" 则程序会输出: 

abc 
acb 
bac 
bca 
cab 
cba 

分析: 

    3-2-1. 算法的出口在于:low=high也就是现在给出的排列元素只有一个时; 

    3-2-2. 算法的逼近过程:先确定排列的第一位元素,也就是循环中i所代表的元素,然后low+1开始减少排列元素,如此下去,直到low=high。(暂未调通) 

Java代码  收藏代码
  1. public static void permute(String str) {   
  2.   char[] strArray = str.toCharArray();   
  3.   permute(strArray, 0, strArray.length - 1);   
  4.   }   
  5.   public static void permute(char[] list, int low, int high) {   
  6.   int i;   
  7.   if (low == high) {   
  8.   String cout = "";   
  9.   for (i = 0; i <= high; i++)   
  10.   cout += list[i];   
  11.   System.out.println(cout);   
  12.   } else {   
  13.   for (i = low; i <= high; i++) {   
  14.   char temp = list[low];   
  15.   list[low] = list[i];   
  16.   list[i] = temp;   
  17.   permute(list, low + 1, high);   
  18.   temp = list[low];   
  19.   list[low] = list[i];   
  20.   list[i] = temp;   
  21.   }   
  22.   }   
  23.   }  

3-3. 这是一个组合的例子,与上述的例子相似,只是它所做的工作是,输出所给字符串中制定数目的元素的组合种类。 

分析: 

    3-3-1. 程序出口在于n=1,此时只要输出目标数组的所有元素即可 

    3-3-2. 逼近过程,当n>1 的时候,我们先取第一个元素放入目标数组中,然后n-1,如此下去,最后出来。

Java代码  收藏代码
  1. import javax.swing.JOptionPane;   
  2. public class Combination {   
  3. /**  
  4. * @param args  
  5. */   
  6. public static void main(String[] args) {   
  7. String input = JOptionPane.showInputDialog("please input your String: ");   
  8. String numString = JOptionPane.showInputDialog("please input the number of your Combination: ");   
  9. int num = Integer.parseInt(numString);   
  10. Combine(input, num);   
  11. }   
  12. private static void Combine(String input, int num) {   
  13. char[] a = input.toCharArray();   
  14. String b = "";   
  15. Combine(a, num, b, 0, a.length);   
  16. }   
  17. private static void Combine(char[] a, int num, String b, int low, int high) {   
  18. if (num == 0) {   
  19. System.out.println(b);   
  20. else {   
  21. for (int i = low; i < a.length; i++) {   
  22. b += a[i];   
  23. Combine(a, num - 1, b, i+1, a.length);   
  24. b=b.substring(0, b.length()-1);   
  25. }   
  26. }   
  27. }   
  28. }  

posted on 2011-07-20 16:12 七孑 阅读(14088) 评论(1)  编辑  收藏 所属分类: 经典算法典藏

评论

# re: Java 排列组合的有趣算法 2014-12-07 21:40 zudaima

java算法demo源代码下载:http://zuidaima.com/share/k%E7%AE%97%E6%B3%95-p1-s1.htm  回复  更多评论   


只有注册用户登录后才能发表评论。


网站导航:
 
<2014年12月>
30123456
78910111213
14151617181920
21222324252627
28293031123
45678910

导航

统计

常用链接

留言簿(1)

随笔分类

随笔档案

文章分类

文章档案

搜索

最新评论

阅读排行榜

评论排行榜