回溯法是暴力法的升级版本,问题的解决是一步一步向下进行的,而每一步又会有有限个选项步,则可以构建一棵多叉树,每个根节点如果匹配则进入该节点的子节点,继续向下匹配,匹配失败则回到父节点的其他子节点向下匹配,如果父节点的所有节点都无法向下匹配成功,则回溯到父节点的父节点,访问爷爷节点的其他字节点,这个过程可以由递归来实现,也就可以用栈来实现和理解。我们便利所有的元素,让其成为入口,也就是根节点,这个时候根节点的方法入栈,如果根节点匹配了,继续向根节点的子节点访问,根节点的子节点的方法入栈,如果该根节的子节点都无法匹配,则该子节点出栈,回溯根节点的其他子节点,继续。如果完全匹配,则返回成功。如果完全便利,都没能匹配,则返回失败。
package jzof_ex;
import java.util.*;
public class Jzof_12 {
class node{
public int x;
public int y;
node(int x,int y){
this.x=x;
this.y=y;
}
}
public boolean hasPath(char[] matrix, int rows, int cols, char[] str) {
if (matrix == null || rows < 0 || cols < 0 || str == null)
return false;
boolean[][] visit = new boolean[rows][cols];
//Stack tmp = new Stack();
int index = 0;
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
if (match(matrix, rows, cols, str, i, j, index, visit)) {
// match()
return true;
}
}
}
return false;
}
public boolean match(char[] matrix, int rows, int cols, char[] str, int i, int j,int index,boolean[][] visit) {
if(index>=str.length) {//如果比较的是index>str.length-1,则当访问到index-2的时候,匹配,index++,则index=str.length-1
//在index=length-1,就返回存在的问题是,字符串的最后一个字符没有匹配
return true;
}
boolean hasmatch=false;
//tmp.push(new node(i,j));
if (i>=0&&i=0&&j
注意
从上面的代码也可以看出来,回溯的实现体现在当前节点的所有子节点都无法匹配的时候,会弹出当前节点。
public class Solution {
public int movingCount(int threshold, int rows, int cols)
{
boolean[][] visit=new boolean[rows][cols];
int num=0;
match(threshold,rows,cols,0,0,visit);
for(int i=0;i0) {
sum=sum+a%10;
a=a/10;
}
return sum;
}
public boolean match(int threshold,int rows,int cols,int i,int j,boolean[][] visit) {
int a = sumEachSite(i) + sumEachSite(j);
boolean hasmatch = false;
if (a <= threshold && i < rows && i >= 0 && j < cols && j >= 0&&visit[i][j] != true) {
visit[i][j] = true;
hasmatch = match(threshold, rows, cols, i, j - 1, visit) || match(threshold, rows, cols, i, j + 1, visit)
|| match(threshold, rows, cols, i - 1, j, visit) || match(threshold, rows, cols, i + 1, j, visit);
}
return hasmatch;
}
}
递归实现计数求和的版本
package jzof_ex;
public class Jzof_13 {
public int movingCount(int threshold, int rows, int cols)
{
boolean[][] visit=new boolean[rows][cols];
int num=Count(threshold,rows,cols,0,0,visit);
return num;
}
public int sumEachSite(int i) {
int a=i;
int sum=0;
while(a>0) {
sum=sum+a%10;
a=a/10;
}
return sum;
}
public int Count(int threshold,int rows,int cols,int i,int j,boolean[][] visit) {
int count=0;
if (match(threshold,rows,cols,i,j,visit)) {
visit[i][j] = true;
count=1+Count(threshold, rows, cols, i, j - 1, visit)+Count(threshold, rows, cols, i, j + 1, visit)
+Count(threshold, rows, cols, i - 1, j, visit)+Count(threshold, rows, cols, i + 1, j, visit);
}
return count;
}
public boolean match(int threshold,int rows,int cols,int i,int j,boolean[][] visit) {
if (sumEachSite(i) + sumEachSite(j)<= threshold && i < rows && i >= 0 && j < cols && j >= 0&&visit[i][j]!=true) {
return true;
}
return false;
}
}
对于递归的理解和回溯法的理解,其实都是对于栈的理解和分治法的理解,当然对于回溯法不能完全说是分治,有点像forkjoinpool的感觉,因为约束条件的不同,使得具体操作会不一样,但是思想都是一样的,我们每一步知道有多少条路,每条路都向下走到黑,成功返回true,失败返回false,同时回溯,把所有的路径遍历一遍即可得到问题的解。当然在就行匹配的时候,或者说约束条件匹配的时候,我们的返回值或者说进行的操作不是固定死的,就比如下面的例子,在匹配成功的时候,我们还进行了计数,所以要理解的更深入些,这是一种解决问题的思想,具体的操作都可以。