今天看了好久的全排列问题!虽然说,之前通过全排列的生成问题算法(上次写的博客里详细讲解了该算法)很完美的解决了这个问题!但是近两天为了更好地理解回溯法!故再次重温全排列的生成问题!
为了更好地说明,我以12345的全排列为例!首先将其放在一个数组中(从小到大),开始循环,如果1234已被选中,那么久需要将1234标记为已选,那么候选元素只剩下5,那么一种全排列也就出来了。显然到这里,需要回溯!那么问题来了,怎么回溯呢?看了之后别人博客上写的算法:意思是这样的!当执行到这里的时候,就将5标记为未选中(此次已成功搜索到一个排列),这时这层循环(第6层)也就结束了。那么自然也就回溯到上一层(第五层),到了第五层,同理4也选完了,自然也标记为未选中了。由于5这个位置空出来了,那么第五层就可以选五,而到了第六层,4被空出来了;那么第六层就自然选4咯!如此回溯,探索!可以得到最终所有解!
好了,思路说完了。代码如下:
1 public class Demo4 { 2 int size; 3 int[] vector;//存储当前解向量 4 boolean[] used;//存储当前解空间中哪些数据已经被使用过 5 int amount = 0; 6 public Demo4(int size){ 7 this.size = size; 8 vector = new int[size]; 9 used = new boolean[size]; 10 } 11 /** 12 * 迭代算法,通过used数组来确定当前层可用解,然后进入下一层重复通用动作。 13 * 当到最终层后修改used数组,回溯。 14 * @param level 当前层,对应为解向量的数组下标。 15 */ 16 public void sort(int level){ 17 for(int i=0;i<size;i++){//从0到size-1,一共size层 18 if(!used[i]){//找到当前层第一个没有被使用的解 19 vector[level]=i;//把这个解赋予解向量的当前层 20 used[i] = true;//标记当前解已经被使用 21 if(level!=size-1)//如果不是最后一层,则递归进行下一层的排序 22 sort(level+1); 23 else 24 System.out.println((++amount)+":"+Arrays.toString(vector));//如果是最后一层,打印输出 25 used[i]=false;//这是回溯的关键! 26 /* 27 * 到达上一条语句的来源,可以分为两种情况: 28 * 1是到达最后一层,i是最后一个可用元素在解空间的下标,自然要将其对应的解“解锁”,即标为未使用。 29 * 2是刚刚推出递归,也就是当前层的解为解空间i的情况刚刚递归完成,所以也要对解进行“解锁”。 30 */ 31 } 32 } 33 } 34 public static void main(String[] args) { 35 new Demo4(6).sort(0); 36 } 37 }
代码上面的注释也写得蛮清楚的,相信各位看官也都看得懂!回溯的关键点之一就是找好回溯点,觉得这个算法真的满巧妙的!通过设置全局变量实现的备选数字的动态变化!真心的要点个赞!
浙公网安备 33010602011771号