算法和数据操作-回溯法

从解决问题的每一步的所有可能选项里系统的选择出一个可行解决方案。回溯法非常适合有多个步骤组成的问题,每个步骤有多个选项,当我们在某一部选择了其中的额一个选项,就进入下一步,然后又面临新的选项。重复选择到达最终状态

用回溯法解决的问题的所有选项可以形象的用树状结构表示。在某一步有n个可能的选项,那么该步骤可以看成是树状结构中的一个节点每个选项看成树中节点连接线,经过这些连接线到达该节点的n个子节点,树的叶节点对应着中介状态。如果在叶节点的状态满足题目的约束条件,那么我们找到了一个可行的解决状态。

如果叶结点的状态不满足约束条件,那么只好回溯到他的上一个节点再尝试其他的选项。如果上一个节点所有可能的选项都已经试过,并且不能到达满足约束条件的终结状态,则回溯到上一个节点。如果所有节点的所有选项都已经尝试过仍然不能满足终结状态,那么无解。

通常回溯法适合用递归实现代码,当我们到达某一结点,尝试所有可能的选项饼并在满足条件的前提下递归的抵达一个节点

 

面试题12.矩阵中的路径

请设计一个函数,用来判断在一个矩阵中是否存在一条包含某字符串给所有字符的路径。路径可以从矩阵中的任意一格开始,每一步可以在矩阵中向左右上下移动一格。如果一条路径经过了矩阵的某一个,那么该路径不能再次进入格子。

思路:

任选一个格子作为路径的起点。假设矩阵中某一个字符是ch,作为第i个字符。如果路径上的第i个字符不是ch,那么这个格子不可能处在路径上的第i个位置。入股哦路径上的第i个字符正好是ch,那么到相邻格子寻找路径上的第i+1个字符。除矩阵边界上的格子之外,其他格子都有4个相邻的格子。重复过程直到所有字符都在矩阵中找到相应的位置

由于回溯法的特殊性质,路径可以被看作一个栈。在前n个字符位置确定后,与第n个字符对应的格子的周围都没有找到第n+1个字符,这时候只好在路径上回到第n-1个字符,重新定位第n个字符。

由于路径上的格子不能重复进入,所以还需要定义一个和字符矩阵大小一样的布尔型矩阵用来标识路径是否已经进入了每个格子。

public class pathMatrix {
    public static boolean hasPath(char[][] matrix,int rows,int columns,String str,int totalLength){
        //如果传入值为空
        if(matrix==null||rows<1||columns<1||str==null){
            return false;
        }
        //标记函数,初始化为false
        Boolean[][] visited = new Boolean[rows][columns];
        for(int i=0;i<rows;i++){
            for(int j=0;j<columns;j++){
                visited[i][j]=false;
            }
        }
        //路径长度
        int pathLength=0;
        //
        for(int i=0;i<rows;i++){
            for(int j=0;j<columns;j++){
                if(hasPathCore(matrix,rows,columns,i,j,str,pathLength,visited,totalLength)){
                    return true;
                }
            }
        }
        return false;
    }

    public static Boolean hasPathCore(char[][] matrix,int rows,int columns,int row,int column,String str,int pathLength,Boolean[][] visited,int totalLength){
        if(pathLength>=totalLength){
            return true;
        }
        Boolean hasPath=false;
        if(row>=0&&row<rows&&column>=0&&column<columns&&matrix[row][column]==str.charAt(pathLength)&&!visited[row][column]){
            ++pathLength;
            visited[row][column]=true;
            hasPath=hasPathCore(matrix,rows,columns,row,column-1,str,pathLength,visited,totalLength)||hasPathCore(matrix,rows,columns,row,column+1,str,pathLength,visited,totalLength)||hasPathCore(matrix,rows,columns,row-1,column,str,pathLength,visited,totalLength)||hasPathCore(matrix,rows,columns,row+1,column,str,pathLength,visited,totalLength);
            if(!hasPath){
                --pathLength;
                visited[row][column]=false;
            }
        }
        return hasPath;
    }
    public static void main(String[] args){
        char[][] matrix={{'a','b','t','g'},{'c','f','c','s'},{'j','d','e','h'}};
        String str="bfce";
        int rows=matrix.length;
        int columns=matrix[0].length;
        int totalLength=str.length();
        System.out.println(hasPath(matrix,rows,columns,str,totalLength));
    }
}

 

理解了上面这题在做下面这题就容易多了

 

面试题13.机器人的运动范围

题目:地上有一个m行n列的耳房各。一个机器人从坐标(0,0)的格子开始移动,他每次可向上下左右移动一格,但不能进入行坐标和列坐标的数位之和大于k的格子。例如当k=18的时候,机器人能进入(35,37),因为3+5+3+7=18,但不能进入方格(35,38),因为3+5+3+8>18

在本地上测试的代码

public class robotMove {
    public static Boolean permitMove(int row,int column,int k){
        int r=row,c=column;
        int ans=0;
        while(r!=0){
            ans=ans+r%10;
            r/=10;
        }
        while(c!=0){
            ans=ans+c%10;
            c/=10;
        }
        if(k>=ans){
            return true;
        }
        else{
            return false;
        }
    }

    public static void move(int[][] visited,int m,int n,int row,int column,int k){
        if(row>=0&&row<m && column>=0&&column<n && visited[row][column]==0 && permitMove(row,column,k)){//当这个格子可以走
            visited[row][column]=1;
            move(visited,m,n,row-1,column,k);
            move(visited,m,n,row+1,column,k);
            move(visited,m,n,row,column-1,k);
            move(visited,m,n,row,column+1,k);
        }
        else{
            return;
        }

    }

    public static int countPlace(int[][] visited,int m,int n){
        int count=0;
        for(int i=0;i<m;i++){
            for(int j=0;j<n;j++){
                if(visited[i][j]==1){
                    count++;
                }
            }
        }
        return count;
    }

    public static void main(String[] args){
        Scanner input = new Scanner((System.in));
        int m = input.nextInt();
        int n = input.nextInt();
        int k = input.nextInt();
        int[][] visited=new int[m][n];
        for(int i=0;i<m;i++){
            for(int j=0;j<n;j++){
                visited[i][j]=0;
            }
        }
        int count=0;
        int row=0,column=0;
        move(visited,m,n,row,column,k);
        System.out.println(countPlace(visited,m,n));
    }
}

放到leetcode上运行

原文地址:https://www.cnblogs.com/ak918xp/p/14451103.html