回溯法+习题(矩阵中的路径,机器人的运动范围(有一个m行和n列的方格。机器人从坐标0,0的格子开始移动,每次只能向左,右,上,下四个方向移动一格,但是不能进入行坐标和列坐标的数位之和大于k的格子))

回溯法:

是一种选优搜索法,又称为试探法,按选优条件向前搜索,以达到目标。但当探索到某一步时,发现原先选择并不优或达不到目标,就退回一步重新选择,这种走不通就退回再走的技术为回溯法,而满足回溯条件的某个状态的点称为“回溯点”。

1.矩阵中的路径

题目描述:

请设计一个函数,用来判断在一个矩阵中是否存在一条包含某字符串所有字符的路径。路径可以从矩阵中的任意一个格子开始,每一步可以在矩阵中向左,向右,向上,向下移动一个格子。如果一条路径经过了矩阵中的某一个格子,则之后不能再次进入这个格子。 例如 a b c e s f c s a d e e 这样的3 X 4 矩阵中包含一条字符串"bcced"的路径,但是矩阵中不包含"abcb"路径,因为字符串的第一个字符b占据了矩阵中的第一行第二个格子之后,路径不能再次进入该格子。

分析:

第一步:创建一个与matrix数组长度相同的boolean型数组,用来标记走过的路径,初始化为false,true表示走过。

第二步:rows,cols表示行,列,因此这里隐含了一个二维数组,元素与matrix相同,通过二维数组的索引便可以计算出在一位数组的位置;遍历数组,先在matrix数组中找到与字符串第一个元素相同的元素的位置(这里的判断是在进入judge函数后第一步判断)

第三步:找到这个元素后判断这个元素是不是字符串的最后一个,是直接返回true

第四步:不是字符串的最后一个,则先将此位置在flag里标记为true,表示已经走过了。

第五步:递归这个元素的上、下、左、右位置,重新进入jude,判断字符串的下一位,若上、下、左、右位置有一个可以走通,就返回true.

第六步:走到这一步说明没有走通,还原路径,将flag中此位置改为false,并返回false。

代码:

扫描二维码关注公众号,回复: 6108456 查看本文章
public class Solution {
    public boolean hasPath(char[] matrix, int rows, int cols, char[] str){
        boolean[] flag = new boolean[matrix.length];//标记走过的路径
        for(int i=0; i<rows; i++){
            for(int j=0; j<cols; j++){
                if(judge(matrix, rows, cols,i,j, flag, str,0)){
                    return true;
                }
            }
        }
        return false;
    }
    public boolean judge(char[] matrix, int rows, int cols,int i,int j,boolean[] flag, char[] str,int k){
        int index = i*cols+j;//一维数组中的索引
        if(i<0 || i>=rows || j<0 || j>=cols || matrix[index]!=str[k] || flag[index] == true){
            return false;
        }
        //判断到最后一个
        if(k==str.length-1){
            return true;
        }
        //当前位已经走过
        flag[index] = true;
        //递归其上、下、左、右
        if(judge(matrix, rows, cols,i-1,j, flag, str,k+1)
          || judge(matrix, rows, cols,i+1,j, flag, str,k+1)
          || judge(matrix, rows, cols,i,j-1, flag, str,k+1)
          || judge(matrix, rows, cols,i,j+1, flag, str,k+1)){
            return true;
        }
        //路径不同,还原路径
        flag[index] = false;
        return false;
    }
}

2.机器人的运动范围

题目描述:

地上有一个m行和n列的方格。一个机器人从坐标0,0的格子开始移动,每一次只能向左,右,上,下四个方向移动一格,但是不能进入行坐标和列坐标的数位之和大于k的格子。 例如,当k为18时,机器人能够进入方格(35,37),因为3+5+3+7 = 18。但是,它不能进入方格(35,38),因为3+5+3+8 = 19。请问该机器人能够达到多少个格子?

分析:

第一步:创建一个行为rows,列为cols的boolean型数组,用来标记走过的位置,初始化为false,true表示走过。

第二步:函数sum (int i,int j)用来计算i,j两数的数位之和。

第三步:judge函数用来递归出可以到达的格子数,judge(int threshold,int rows, int cols, boolean[][] flag,int i,int j),返回值为Int。

第四步:进入judge函数,判断i,j是否越界,或sum (i, j) > threshold 或 flag[i][j] == true,满足其一,说明不能走这个格子或者这个格子已经走过了,并在计数,返回0。

第五步:不满足第四步的判断,将此格子在flag中标记为true,标记走过了。

第六步:递归这个位置的上、下、左、右,返回递归的上、下、左、右再加1(加上自己)的和。

第七步:在movingCount函数中调用judge函数,初始的位置即i=0,j=0,让其帝国出结果直接返回。

代码:

public class Solution {
    public int movingCount(int threshold, int rows, int cols){
        boolean[][] flag = new boolean[rows][cols];//标记
        return judge(threshold,rows,cols, flag,0,0);
    }
    private int judge(int threshold,int rows, int cols, boolean[][] flag,int i,int j){
        if(i<0 || i>=rows || j<0 || j>=cols ||sum(i,j) > threshold || flag[i][j] == true){
            return 0;
        }
        flag[i][j] = true;//标记走过
        return judge(threshold,rows,cols, flag,i-1,j)
            + judge(threshold,rows,cols, flag,i+1,j)
            + judge(threshold,rows,cols, flag,i,j-1)
            + judge(threshold,rows,cols, flag,i,j+1)+1;
    }
    //计算i,j的数位之和
    private int sum (int i,int j){
        int sum = 0;
        while(i != 0){
            sum += i%10;
            i = i/10;
        }
        while(j != 0){
            sum += j%10;
            j = j/10;
        }
        return sum;
    }
}

猜你喜欢

转载自blog.csdn.net/qq_43109561/article/details/89670163