目录
回溯法
回溯法(探索与回溯法)是一种选优搜索法,又称为试探法,按选优条件向前搜索,以达到目标。但当探索到某一步时,发现原先选择并不优或达不到目标,就退回一步重新选择,这种走不通就退回再走的技术为回溯法,而满足回溯条件的某个状态的点称为“回溯点”。
通常回溯法算法适合用递归实现代码。
65.矩阵中的路径
请设计一个函数,用来判断在一个矩阵中是否存在一条包含某字符串所有字符的路径。路径可以从矩阵中的任意一个格子开始,每一步可以在矩阵中向左,向右,向上,向下移动一个格子。如果一条路径经过了矩阵中的某一个格子,则之后不能再次进入这个格子。 例如 a b t g c f c s j d e h 这样的3 X 4 矩阵中包含一条字符串"bfce"的路径,但是矩阵中不包含"abfb"路径,因为字符串的第一个字符b占据了矩阵中的第一行第二个格子之后,路径不能再次进入该格子。
时间限制:1秒 空间限制:32768K
分析:这是一个可以用回溯法解决的典型题。首先,在矩阵中任选一个格子作为路径的起点。假设矩阵中某个格子的字符为c,并且这个字符将对应路径上的第i个字符。如果路径上的第i个字符与这个格子的字符不相等,则说明这个格子不是处于路径上的第i个位置。如果路径上的第i个字符与这个格子的字符相等,那么就可以去与这个格子相邻的格子上去找路径上的第i+1个位置。除矩阵边界上的格子之外,其他格子都有4个相邻的格子。重复这个过程,直到路径上的所有字符都在矩阵中找到相应的位置。
function hasPath(matrix, rows, cols, path){
if(matrix==undefined||rows<=0||cols<=0||path.length<0){
return false;
}
var visited=new Array();
for(var i=0;i<rows*cols;i++){
visited[i]=false;
}
var pathLength = 0;
for(var row = 0; row < rows; ++row){
for(var col = 0; col < cols; ++col){
if(hasPathCore(matrix, rows, cols, row, col, path,
pathLength, visited))
{
return true;
}
}
}
visited.length=0;
return false;
}
function hasPathCore(matrix,rows,cols,row,col,path,pathLength,visited){
if(path.length == pathLength){
return true;
}
var hasPath=false;
if(row >= 0 && row < rows && col >= 0 && col < cols
&& matrix[row * cols + col] == path[pathLength]
&& !visited[row * cols + col]){
pathLength++;
visited[row*cols+col]=true;
hasPath=hasPathCore(matrix,rows,cols,row,col-1,
path,pathLength,visited)
||hasPathCore(matrix,rows,cols,row-1,col,
path,pathLength,visited)
||hasPathCore(matrix,rows,cols,row,col+1,
path,pathLength,visited)
||hasPathCore(matrix,rows,cols,row+1,col,
path,pathLength,visited);
if(!hasPath){
--pathLength;
visited[row * cols + col] = false;
}
}
return hasPath;
}
66.机器人的运动范围
地上有一个m行和n列的方格。一个机器人从坐标0,0的格子开始移动,每一次只能向左,右,上,下四个方向移动一格,但是不能进入行坐标和列坐标的数位之和大于k的格子。 例如,当k为18时,机器人能够进入方格(35,37),因为3+5+3+7 = 18。但是,它不能进入方格(35,38),因为3+5+3+8 = 19。请问该机器人能够达到多少个格子?
时间限制:1秒 空间限制:32768K
分析:和上一道题类似,这个方格也可以看作一个mxn的矩阵,同样,在这个矩阵中,除边界上的格子之外,其他格子都有4个相邻的格子。机器人从坐标(0,0)开始移动。当它准备进入坐标为(i,j)的格子时,通过检查坐标的位数的和来判断机器人是否能够进入。如果机器人能够进入坐标为(i,j)的格子,则再判断机器人能否进入4个相邻的格子(i-1,j),(i,j-1),(i+1,j),(i,j+1)。因此可以用如下代码来实现回溯算法:
function movingCount(threshold, rows, cols){
if(threshold<0||rows<=0||cols<=0){
return 0;
}
var visited=new Array();
for(var i=0;i<rows*cols;i++){
visited[i]=false;
}
var count=movingCountCore(threshold,rows,cols,0,0,visited);
delete visited;
return count;
}
function movingCountCore(threshold,rows,cols,row,col,visited){
var count=0;
if(check(threshold,rows,cols,row,col,visited)){
visited[row*cols+col]=true;
count=1+movingCountCore(threshold,rows,cols,row-1,col,visited)
+movingCountCore(threshold,rows,cols,row,col-1,visited)
+movingCountCore(threshold,rows,cols,row+1,col,visited)
+movingCountCore(threshold,rows,cols,row,col+1,visited);
}
return count;
}
function check(threshold,rows,cols,row,col,visited){
if(row>=0&&row<rows&&col>=0&&col<cols&&
getDigitSum(row)+getDigitSum(col)<=threshold
&&!visited[row*cols+col])
return true;
return false;
}
function getDigitSum(number){
var sum=0;
while(number>0)
{
sum+=number%10;
number=Math.floor(number / 10);
}
return sum;
}