【算法训练】LeetCode#79 单词搜索

一、描述

79. 单词搜索

给定一个 m x n 二维字符网格 board 和一个字符串单词 word 。如果 word 存在于网格中,返回 true ;否则,返回 false

单词必须按照字母顺序,通过相邻的单元格内的字母构成,其中“相邻”单元格是那些水平相邻或垂直相邻的单元格。同一个单元格内的字母不允许被重复使用。

示例 1:

输入:board = [["A","B","C","E"],["S","F","C","S"],["A","D","E","E"]], word = "ABCCED"
输出:true

示例 2:

输入:board = [["A","B","C","E"],["S","F","C","S"],["A","D","E","E"]], word = "SEE"
输出:true

示例 3:

输入:board = [["A","B","C","E"],["S","F","C","S"],["A","D","E","E"]], word = "ABCB"
输出:false

二、思路

深度优先搜索+回溯吧...

三、解题


public class LeetCode79 {

    public static void main(String[] args) {
        System.out.println(existOne(new char[][]{{'A','B','C','E'},{'S','F','E','S'},{'A','D','E','E'}},"ABCESEEEFS"));
    }
//    {'A','B','C','E'},
//    {'S','F','E','S'},
//    {'A','D','E','E'}
    public static boolean existOne(char[][] board, String word) {
        int m = board.length;
        int n= board[0].length;
        int targetLen = word.length();
        for (int i = 0 ; i < m ; i++){
            for (int j = 0 ; j < n ; j++){
                if (processOne(board,word,i,j,m,n,0,targetLen,new HashSet<String>())){
                    return true;
                }
            }
        }
        return false;
    }

    public static boolean processOne(char[][] board,String word,int x,int y,int m,int n,int curLen,int targetLen,HashSet<String> over){
        String curLoc = x + String.valueOf(y);
        if (x < 0 || y < 0 || x >= m || y >= n || over.contains(curLoc) || curLen + 1 > targetLen){
            // 越界了或已遍历或再加一个长度多了
            return false;
        }
        curLen++;

        if (curLen == targetLen){
            // 长度相等时,判断最后一个是否相等,相等则匹配
            return word.charAt(curLen-1) == board[x][y];
        }
        over.add(curLoc);
        if (word.charAt(curLen-1) == board[x][y]){
            boolean flag = processOne(board, word, x, y + 1, m, n, curLen, targetLen, over);
            if (flag){
                over.remove(x + String.valueOf(y+1));
                return true;
            }
            flag = processOne(board, word, x, y - 1, m, n, curLen, targetLen, over);
            if (flag){
                over.remove(x + String.valueOf(y-1));
                return true;
            }
            flag = processOne(board, word, x + 1, y, m, n, curLen, targetLen, over);
            if (flag){
                over.remove((x+1) + String.valueOf(y));;
                return true;
            }
            flag = processOne(board, word, x - 1, y, m, n, curLen, targetLen, over);
            if (flag){
                over.remove((x-1) + String.valueOf(y));
                return true;
            }
        }
        over.remove(curLoc);
        return false;
    }



//    方法二做了一些优化,但是得分还是不高。。。
    public static boolean existTwo(char[][] board, String word) {
        int m = board.length;
        int n= board[0].length;
        int targetLen = word.length();
        for (int i = 0 ; i < m ; i++){
            for (int j = 0 ; j < n ; j++){
                if (processTwo(board,new boolean[m][n],i,j,word,0,targetLen)){
                    return true;
                }
            }
        }
        return false;
    }

    public static boolean processTwo(char[][] board,boolean[][] visited,int i,int j,String target,int k,int targetLen){
        if (target.charAt(k) != board[i][j]){
            return false; // 如果不等就不用继续了
        } else if(k == targetLen-1){
            return true; // 比到最后且相等则true,结束条件
        }

        visited[i][j] = true; // 标记已访问
        int[][] directions = {{0,1},{0,-1},{1,0},{-1,0}};
        boolean result = false;
        for (int[] dir : directions){
            int newI = i + dir[0];
            int newJ = j + dir[1];
            // 模拟上下左右
            if (newI >= 0 && newI < board.length && newJ >= 0 && newJ <= board[0].length){
                if (!visited[newI][newJ]){
                    // 且当前路径为访问过
                    boolean flag = processTwo(board,visited,newI,newJ,target,k+1,targetLen);
                    if (flag){
                        // 如果true
                        result = true;
                        break;
                    }
                }
            }
        }
        visited[i][j] = false; // 剪枝
        return result;
    }
}
posted @ 2023-03-17 15:11  小拳头呀  阅读(10)  评论(0编辑  收藏  举报