1回溯法
回溯法就是,当你面对很多个选择的时候,先随便选一个,做下去,发现不行的时候,再倒回之前选择的情况,重新选择,直到把所有可能性试完。java解决
2,经典八皇后问题
class Solution {
public boolean check(int[] arr,int i,int k){
for(int j=0;j<i;j++){
if(arr[j]==k||Math.abs(j-i)==Math.abs(arr[j]-k)){
return false;
}
}
return true;
}
public int f(int i,int n,int[] arr){
int sum=0;
if(i==n){
return 1;
}
for(int k=0;k<=n-1;k++){
if(check(arr,i,k)){
arr[i]=k;
sum+=f(i+1,n,arr);
}
}
return sum;
}
public int totalNQueens(int n) {
int[] arr=new int[n];
if(n<=0){
return 0;
}
return f(0,n,arr);
}
}
1,首先需要数组来记录放过皇后的位置,这里可以采用一维数组,不用二维数组。
因为只是记录格子的两个坐标,不需要记录格子具体的数值。因此,一维数组足够。
2,对于check函数
public boolean check(int[] arr,int i,int k){
for(int j=0;j<i;j++){
if(arr[j]==k||Math.abs(j-i)==Math.abs(arr[j]-k)){
return false;
}
}
return true;
}
由于是从行开始遍历,所以只需要确认同一列是否有两个皇后和斜线是否有两个皇后。
3,这一步就是回溯过程
for(int k=0;k<=n-1;k++){
if(check(arr,i,k)){
arr[i]=k;
sum+=f(i+1,n,arr);
}
}
从第i行的第0个元素开始,依次选择
3,数独
class Solution {
boolean[][] row=new boolean[9][10];
boolean[][] col=new boolean[9][10];
boolean[][] area=new boolean[9][10];
boolean finish=false;
public void f(char[][] board,int index){
if(index==81){
finish=true;
return;
}
int ro=index/9;
int co=index%9;
if(board[ro][co]!='.'){
f(board,index+1);
}else{
for(int i=1;i<=9;i++){
if(!row[ro][i]&&!col[co][i]&&!area[3*(ro/3)+co/3][i]){
row[ro][i]=true;
col[co][i]=true;
area[3*(ro/3)+co/3][i]=true;
board[ro][co]=(char)(i+'0');
f(board,index+1);
if(finish){
return;
}
row[ro][i]=false;
col[co][i]=false;
area[3*(ro/3)+co/3][i]=false;
board[ro][co]='.';
}
}
}
}
public void solveSudoku(char[][] board) {
for(int i=0;i<=8;i++){
for(int j=1;j<=9;j++){
row[i][j]=false;
col[i][j]=false;
area[i][j]=false;
}
}
for(int i=0;i<=8;i++){
for(int j=0;j<=8;j++){
int val=board[i][j]-'0';
if(board[i][j]!='.'){
row[i][val]=true;
col[j][val]=true;
area[3*(i/3)+(j/3)][val]=true;
}
}
}
f(board,0);
return;
}
}
1,由于数独有行,列以及九宫格的限制
因此需要三个二维数组来分别记录行,列,九宫格的限制
boolean[][] row=new boolean[9][10];
boolean[][] col=new boolean[9][10];
boolean[][] area=new boolean[9][10];
对于row[3][5]=true的意思
row代表行
整句意思是:对于第三行,5这个数字存在
2,开头是初始化三个二维数组
for(int i=0;i<=8;i++){
for(int j=1;j<=9;j++){
row[i][j]=false;
col[i][j]=false;
area[i][j]=false;
}
}
for(int i=0;i<=8;i++){
for(int j=0;j<=8;j++){
int val=board[i][j]-'0';
if(board[i][j]!='.'){
row[i][val]=true;
col[j][val]=true;
area[3*(i/3)+(j/3)][val]=true;
}
}
}
先全部初始化为false。然后再分别对已经填了数的格子,完善三个二维数组。
3,这一步是如果index这个格子已经填了数,那就跳到下一个格子
if(board[ro][co]!='.'){
f(board,index+1);
}else
4,这一步可以通过行和列确定这个格子处于哪一个九宫格(从左上开始数)
3*(row/3)+col/3
5,这一步就是回溯过程
for(int i=1;i<=9;i++){
if(!row[ro][i]&&!col[co][i]&&!area[3*(ro/3)+co/3][i]){
row[ro][i]=true;
col[co][i]=true;
area[3*(ro/3)+co/3][i]=true;
board[ro][co]=(char)(i+'0');
f(board,index+1);
从第index个格子开始,依次尝试1到9个数字,剩下的交给递归
6,一定要记得回溯算法,要还原犯罪现场
row[ro][i]=false;
col[co][i]=false;
area[3*(ro/3)+co/3][i]=false;
board[ro][co]='.';
这一种情况不行,要把这一种情况造成的影响还原,方便继续尝试后面的情况