搜索与回溯算法-Java实现

一、概述

1.定义

  • 搜索与回溯是计算机解题中常用的算法,很多问题无法根据某种确定的计算法则来求解,可以利用搜索与回溯的技术求解。回溯是搜索算法中的一种控制策略。
  • 它的基本思想是:为了求得问题的解,先选择某一种可能情况向前探索,在探索过程中,一旦发现原来的选择是错误的,就退回一步重新选择,继续向前探索,如此反复进行,直至得到解或证明无解。
  • 如迷宫问题:进入迷宫后,先随意选择一个前进方向,一步步向前试探前进,如果碰到死胡同,说明前进方向已无路可走,这时,首先看其它方向是否还有路可走,如果有路可走,则沿该方向再向前试探;如果已无路可走,则返回一步,再看其它方向是否还有路可走;如果有路可走,则沿该方向再向前试探。按此原则不断搜索回溯再搜索,直到找到新的出路或从原路返回入口处无解为止。

2.算法框架

int search(int k){
    for(int i=1;i<=算符种类;i++){
        if(符合条件){
            保存条件
            if (到目的地) 输出结果
            else search(k + 1);
            回溯,把保存的结果回退
        }
    }
}

二、示例

1.矩阵寻径

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

【代码】

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

    /**
     * 个人思路:
     * 1.把一维数组变成二维数组,并额外设置一个标记数组,用来判断是否已经经过
     * 2.构建一个位移数组,分别代表上下左右的移动,注意边界的判断
     * */



public boolean hasPath(char[] matrix, int rows, int cols, char[] str) {

    // 标记数组
    boolean[][] flag = new boolean[rows][cols];
    // 存储为二维数组
    char[][] max = new char[rows][cols];
    for (int i=0; i<rows; i++) {
        for(int j=0; j<cols; j++) {
            max[i][j] = matrix[cols*i + j];
        }
    }

    for (int i=0; i<rows; i++) {
        for(int j=0; j<cols; j++) {
            if (search(0,max,i,j,rows,cols,str,flag)) {
                return true;
            }
        }
    }
    return false;
}

// 构建位移数组,0,1,2,3分别代表上、右、下、左
int[][] move ={{-1,0},{0,1},{1,0},{0,-1}};

// 搜索回溯
public boolean search(int n, char[][] max, int i, int j, int rows, int cols, char[] str, boolean[][] flag) {
    // 当前的字符与矩阵中的某个位置的字符相同
    if (str[n] == max[i][j] && !flag[i][j]) {
        flag[i][j] = true;
        // 到达终点
        if (str.length-1 == n) {
            return true;
        }
        //  上下左右没有越界
        if (i-1 >= 0  && search(n + 1, max, i - 1, j, rows, cols, str, flag)) {
            return true;
        }
        if (j+1 < cols && search(n + 1, max, i, j+1, rows, cols, str, flag)) {
            return true;
        }
        if (i+1 < rows && search(n + 1, max, i+1, j, rows, cols, str, flag)) {
            return true;
        }
        if (j-1 >= 0 && search(n + 1, max, i, j-1, rows, cols, str, flag)) {
            return true;
        }
        flag[i][j] = false;
    }
    return false;
}

PS:关于递归方法的一些思考
如果递归方法的返回值是boolean类型,那么,把递归方法作为判断条件来返回是较好的选择,具体例子见上述方法递归的使用。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
回溯算法是一种经典的搜索算法,Java语言可以通过递归来实现回溯算法回溯算法通常用于求解一个问题的所有可能解或最优解。该算法通过尝试所有可能的解来解决问题,然后回溯(返回上一个状态)并尝试其他可能的解,直到找到解决方案或者所有可能的解都已经尝试过。 下面是Java实现回溯算法的一般步骤: 1. 确定问题的解空间:即确定问题的所有可能解组成的集合。 2. 确定约束条件:即问题需要满足的条件。 3. 确定搜索策略:即在问题解空间中进行搜索的方式。 4. 实现回溯算法:通过递归实现,对问题的所有可能情况进行搜索,并返回找到的解或无解。 下面是一个简单的Java代码实现回溯算法的例子,该例子用回溯算法求解数独问题: ``` public class SudokuSolver { public void solveSudoku(char[][] board) { if (board == null || board.length == 0) { return; } solve(board); } private boolean solve(char[][] board) { for (int i = 0; i < board.length; i++) { for (int j = 0; j < board.length; j++) { if (board[i][j] == '.') { for (char c = '1'; c <= '9'; c++) { if (isValid(board, i, j, c)) { board[i][j] = c; if (solve(board)) { return true; } else { board[i][j] = '.'; } } } return false; } } } return true; } private boolean isValid(char[][] board, int row, int col, char c) { for (int i = 0; i < 9; i++) { if (board[i][col] != '.' && board[i][col] == c) { return false; } if (board[row][i] != '.' && board[row][i] == c) { return false; } if (board[3 * (row / 3) + i / 3][3 * (col / 3) + i % 3] != '.' && board[3 * (row / 3) + i / 3][3 * (col / 3) + i % 3] == c) { return false; } } return true; } } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值