package leecode;
/**
 * 剑指 Offer 12. 矩阵中的路径
 *
 * 给定一个 m x n 二维字符网格 board 和一个字符串单词 word 。如果 word 存在于网格中,返回 true ;否则,返回 false 。
 *
 * 单词必须按照字母顺序,通过相邻的单元格内的字母构成,其中“相邻”单元格是那些水平相邻或垂直相邻的单元格。同一个单元格内的字母不允许被重复使用。
 *
 *  
 *
 * @author Tang
 * @date 2021/12/16
 */
public class Exist {
    char[][] board;
    char[][] hasChoose;
    char[] words;
    /**
     * 回溯法
     * 把word逐个拆开 挨个判断
     * 1.先顺序遍历二维数组找到首个word
     * 2.以下一个word,和上一个word的横纵坐标进行递归。 分别判断他的上下左右是否有合适的下一个word
     * 3.有合适的word则加入hasChoose,避免重复占用元素
     * 4.撤销选择 元素移出hasChoose
     * 
     * @param board
     * @param word
     * @return
     */
    public boolean exist(char[][] board, String word) {
        this.board = board;
        //单词数组
        words = word.toCharArray();
        //保存已选择过的位置
        //选择过为1
        hasChoose = new char[board.length][board[0].length];
        //遍历整个二维数组
        //找到第一个字母位置执行递归
        for(int i = 0; i < board.length; i++) {
            for(int j = 0; j < board[i].length; j++) {
                if(board[i][j] == words[0]) {
                    hasChoose[i][j] = 1;
                    if(track(1, i, j)) {
                        return true;
                    }
                    hasChoose[i][j] = 0;
                }
            }
        }
        return false;
    }
    /**
     * 目的;判断上一个选择元素的上下左右位置是否有合适的word
     *
     * @param i 当前要找的words索引 words[i]
     * @param rowIndex 上一个选择元素是第几行
     * @param heightIndex 上一个选择元素第几列
     */
    private boolean track(int i, int rowIndex, int heightIndex) {
        //所有word都找完了 成功结束
        if(i >= words.length) {
            return true;
        }
        //分别上下左右走一遍
        return checkAndProcess(i, rowIndex - 1, heightIndex) ||
                checkAndProcess(i, rowIndex + 1, heightIndex) ||
                checkAndProcess(i, rowIndex, heightIndex - 1) ||
                checkAndProcess(i, rowIndex, heightIndex + 1);
    }
    /**
     * 判断该位置是否符合word条件
     * 如果符合 执行递归
     * 递归后撤销选择
     *
     * @param rowIndex
     * @param heightIndex
     */
    private boolean checkAndProcess(int i, int rowIndex, int heightIndex) {
        if(rowIndex >= board.length || rowIndex < 0 ||
                heightIndex >= board[rowIndex].length ||heightIndex < 0 ) {
            return false;
        }
        //递归前做出选择
        //判断board[rowIndex][heightIndex]是否是合适word
        //如果不为word或者已经被占用过了
        if(board[rowIndex][heightIndex] != words[i] || hasChoose[rowIndex][heightIndex] == 1) {
            return false;
        }
        hasChoose[rowIndex][heightIndex] = 1;
        //执行递归
        if(track(i + 1, rowIndex, heightIndex)){
            return true;
        }
        //递归后撤销选择
        hasChoose[rowIndex][heightIndex] = 0;
        return false;
    }
    public static void main(String[] args) {
//        char[][] board = {
//                {'A', 'B', 'C', 'E'},
//                {'S', 'F', 'C', 'S'},
//                {'A', 'D', 'E', 'E'}
//        };
        char[][] board = {
                {'a'},
                {'b'}
        };
        System.out.println(new Exist().exist(board, "ba"));
    }
}