简单易理解的回溯法,高效判断素数,可以看我另外两篇博客,这里我也快速简要讲一下。
这一题主要是要领悟回溯法,很关键。
先写一个正常的n个数的求各种排列情况。就1到。。n。的各种排列情况。
方法:正常思路是第一个位置有n种情况,你要写一个长度n的for循环,第二个位置自然是n-1种情况,所以要写一个长度n的for循环,以此类推。。。但是问题来了,你怎么知道传进来的n是多少?你又要写几个for循环?所以你需要用回溯法来递归处理这个情况(当然也有不用递归的方法)。你需要写这样一个方法:你需要写一个标记数组,用来标记这个数字是否访问过了。还有一个标记当前正在处理哪个位数的level,如果level是0,那就是正在为第一位找,所以说不管从哪个位置开始找,方法都是一样的,唯一不同的是你正在为哪一位找以及有哪些数组已经用过了。
上代码
private void sort(int level) { for (int i = 0; i < n; i ++) { if (!flag[i]) { current[level] = i + 1; flag[i] = true;//比如倒数第二层:锁一个 if (level != n - 1) { sort(level + 1);//留一个给最后一层 } else { System.out.println(Arrays.toString(current)); } flag[i] = false;//最后一层搞完后,恢复这一层,让剩下那个数再搞 } } }当你在最后一层的时候,就只能找到一个数了,就返回上一个循环,上一个循环可以找到两个数,第一个数已经找到符合的情况了,再用第二个数。再上一层也是一,以此类推。那么我们是怎么样实现这个回溯的功能的呢?其实for循环和递归写在那里了,他本身就可以回溯回去。我们唯一要做的就是,开始进入下一个循环之前,把当前的数标记为已经访问,完全退出下一个循环后,再把当前的数标记为未访问状态,当前的循环再去找下一个数。
讲的有点长,还是得去看看我原来的文章,讲的又简单又清楚。
[1, 2, 3, 4]
[1, 2, 4, 3]
[1, 3, 2, 4]
[1, 3, 4, 2]
[1, 4, 2, 3]
[1, 4, 3, 2]
[2, 1, 3, 4]
[2, 1, 4, 3]
[2, 3, 1, 4]
[2, 3, 4, 1]
[2, 4, 1, 3]
[2, 4, 3, 1]
。。。
可以看到已经成功输出了,搞定了回溯法后就可以轻松解决这个问题了,只需要在代码里改动小小的地方即可。
针对这题,就是:1.修改一下一个if语句,
if (!flag[i] && isPrime(current[level - 1] + i + 1)) {与上一个数之和为素数
2.1不用放入回溯法内
public class PrimeRingProblem1016 { private int n; private int[] current; private boolean[] flag; PrimeRingProblem1016(int n) { this.n = n; current = new int[n]; flag = new boolean[n]; current[0] = 1; } //高效判断素数 private boolean isPrime(int num) { if (num == 2 || num == 3) { return true; } //如果不在6的倍数附近,肯定不是素数 if (num % 6 != 1 && num % 6 != 5) { return false; } //对6倍数附近的数进行判断 //这里添加了一个num % (i + 2) == 0,为什么? //枚举一下i,i+2可能的取值,因为i +=6 //所以是这样的 5 7,11 13,17 19 //为什么呢?举一个35(=36-1)的情况,是5和7的倍数 //再举一个 49(=48+1),是7的倍数 //所以知道了,6附近的两个数不一定是质数,有可能是5和7的倍数 for (int i = 5; i <= Math.sqrt(num); i += 6) { if (num % i == 0 || num % (i + 2) == 0) { return false; } } return true; } private void sort(int level) { for (int i = 1; i < n; i++) { if (!flag[i] && isPrime(current[level - 1] + i + 1)) { current[level] = i + 1; flag[i] = true; if (level != n - 1) { sort(level + 1); } else { System.out.println(Arrays.toString(current)); } flag[i] = false; } } } public static void main(final String[] args) throws Exception { PrimeRingProblem1016 primeRingProblem1016 = new PrimeRingProblem1016(6); primeRingProblem1016.sort(1); } }
我好想忘了1和最后一个数判断了,不过,没关系吧。。。