zoukankan      html  css  js  c++  java
  • LeetCode——79. 单词搜索

    给定一个二维网格和一个单词,找出该单词是否存在于网格中。

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

    示例:

    board =
    [
      ['A','B','C','E'],
      ['S','F','C','S'],
      ['A','D','E','E']
    ]
    
    给定 word = "ABCCED", 返回 true.
    给定 word = "SEE", 返回 true.
    给定 word = "ABCB", 返回 false.
    

    https://leetcode-cn.com/problems/word-search/

    深度优先遍历 DFS

    原二维数组就像是一个迷宫,可以上下左右四个方向行走,我们以二维数组中每一个数都作为起点和给定字符串做匹配,

    我们还需要一个和原数组等大小的 visited 数组,是 bool 型的,用来记录当前位置是否已经被访问过,因为题目要求一个 cell 只能被访问一次。

    如果二维数组 board 的当前字符和目标字符串 word 对应的字符相等,则对其上下左右四个邻字符分别调用 DFS 的递归函数,只要有一个返回 true,那么就表示可以找到对应的字符串,否则就不能找到,具体看代码实现如下:

    c++

    class Solution {
    public:
        bool exist(vector<vector<char>>& board, string word) {
            if (board.empty() || board[0].empty()) return false;
            int m = board.size(), n = board[0].size();
            vector<vector<bool>> visited(m, vector<bool>(n));
            
            for (int i = 0; i < m; ++i) {
                for (int j = 0; j < n; ++j) {
                    if (search(board, word, 0, i, j, visited)) return true;
                }
            }
            return false;
        }
        bool search(vector<vector<char>>& board, string word, int idx, int i, int j, vector<vector<bool>>& visited) {
            if (idx == word.size()) return true;
            int m = board.size(), n = board[0].size();
            
            if (i < 0 || j < 0 || i >= m || j >= n || visited[i][j] || board[i][j] != word[idx]) return false;
            
            visited[i][j] = true;
            bool res = search(board, word, idx + 1, i - 1, j, visited) 
                     || search(board, word, idx + 1, i + 1, j, visited)
                     || search(board, word, idx + 1, i, j - 1, visited)
                     || search(board, word, idx + 1, i, j + 1, visited);
            visited[i][j] = false;
            
            return res;
        }
    };
    

    java

    public class Solution {
    
        private boolean[][] marked;
        //        x-1,y
        // x,y-1  x,y    x,y+1
        //        x+1,y
        private int[][] direction = {{-1, 0}, {0, -1}, {0, 1}, {1, 0}};
        private int m; // 盘面上有多少行
        private int n; // 盘面上有多少列
        private String word;
        private char[][] board;
    
        public boolean exist(char[][] board, String word) {
            m = board.length;
            if (m == 0) {
                return false;
            }
            n = board[0].length;
            marked = new boolean[m][n];
            this.word = word;
            this.board = board;
    
            for (int i = 0; i < m; i++) {
                for (int j = 0; j < n; j++) {
                    if (dfs(i, j, 0)) {
                        return true;
                    }
                }
            }
            return false;
        }
        
        private boolean inArea(int x, int y) {
            return x >= 0 && x < m && y >= 0 && y < n;
        }
    
        private boolean dfs(int i, int j, int start) {
            if (start == word.length() - 1) {
                return board[i][j] == word.charAt(start);
            }
            if (board[i][j] == word.charAt(start)) {
                marked[i][j] = true;
                for (int k = 0; k < 4; k++) {
                    int newX = i + direction[k][0];
                    int newY = j + direction[k][1];
                    if (inArea(newX, newY) && !marked[newX][newY]) {
                        if (dfs(newX, newY, start + 1)) {
                            return true;
                        }
                    }
                }
                marked[i][j] = false;
            }
            return false;
        }
    }
    

    python

    from typing import List
    
    class Solution:
        #         (x-1,y)
        # (x,y-1) (x,y) (x,y+1)
        #         (x+1,y)
        directions = [(0, -1), (-1, 0), (0, 1), (1, 0)]
    
        def exist(self, board: List[List[str]], word: str) -> bool:
            m = len(board)
            if m == 0:
                return False
            n = len(board[0])
    
            marked = [[False for _ in range(n)] for _ in range(m)]
            for i in range(m):
                for j in range(n):
                    # 对每一个格子都从头开始搜索
                    if self.__search_word(board, word, 0, i, j, marked, m, n):
                        return True
            return False
    
        def __search_word(self, board, word, index,
                          start_x, start_y, marked, m, n):
            # 先写递归终止条件
            if index == len(word) - 1:
                return board[start_x][start_y] == word[index]
    
            # 中间匹配了,再继续搜索
            if board[start_x][start_y] == word[index]:
                # 先占住这个位置,搜索不成功的话,要释放掉
                marked[start_x][start_y] = True
                for direction in self.directions:
                    new_x = start_x + direction[0]
                    new_y = start_y + direction[1]
                    # 注意:如果这一次 search word 成功的话,就返回
                    if 0 <= new_x < m and 0 <= new_y < n and 
                            not marked[new_x][new_y] and 
                            self.__search_word(board, word,
                                               index + 1,
                                               new_x, new_y,
                                               marked, m, n):
                        return True
                marked[start_x][start_y] = False
            return False
    

    改进

    我们还可以不用 visited 数组,直接对 board 数组进行修改,将其遍历过的位置改为井号,记得递归调用完后需要恢复之前的状态,参见代码如下:

    c++

    class Solution {
    public:
        bool exist(vector<vector<char>>& board, string word) {
            if (board.empty() || board[0].empty()) return false;
            int m = board.size(), n = board[0].size();
            for (int i = 0; i < m; ++i) {
                for (int j = 0; j < n; ++j) {
                    if (search(board, word, 0, i, j)) return true;
                }
            }
            return false;
        }
        bool search(vector<vector<char>>& board, string word, int idx, int i, int j) {
            if (idx == word.size()) return true;
            int m = board.size(), n = board[0].size();
            if (i < 0 || j < 0 || i >= m || j >= n || board[i][j] != word[idx]) return false;    
            char c = board[i][j];
            board[i][j] = '#';
            bool res = search(board, word, idx + 1, i - 1, j) 
                     || search(board, word, idx + 1, i + 1, j)
                     || search(board, word, idx + 1, i, j - 1)
                     || search(board, word, idx + 1, i, j + 1);
            board[i][j] = c;
            return res;
        }
    };
    
  • 相关阅读:
    dotnetcharting 生成柱状图,饼图等统计图
    asp.net 前后台相互调用
    SQL基础和高级(语法格式)总结二
    自己动手JQuery插件开发
    SQL基础之创建数据库,表,架构
    SQL基础和高级(语法格式)总结一
    ado.net总结
    [Nescafé 26] 小猫爬山&&售货员的难题&&区间众数(随机化大法好)
    POJ2774 后缀自动机&后缀数组
    【方向学习】单片机
  • 原文地址:https://www.cnblogs.com/wwj99/p/12356348.html
Copyright © 2011-2022 走看看