leetcode刷题笔记 212题 单词搜索 II

leetcode刷题笔记 212题 单词搜索 II

源地址:212. 单词搜索 II

问题描述:

给定一个二维网格 board 和一个字典中的单词列表 words,找出所有同时在二维网格和字典中出现的单词。

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

示例:

输入:
words = ["oath","pea","eat","rain"] and board =
[
['o','a','a','n'],
['e','t','a','e'],
['i','h','k','r'],
['i','f','l','v']
]

输出: ["eat","oath"]
说明:
你可以假设所有输入都由小写字母 a-z 组成。

提示:

你需要优化回溯算法以通过更大数据量的测试。你能否早点停止回溯?
如果当前单词不存在于所有单词的前缀中,则可以立即停止回溯。什么样的数据结构可以有效地执行这样的操作?散列表是否可行?为什么? 前缀树如何?如果你想学习如何实现一个基本的前缀树,请先查看这个问题: 实现Trie(前缀树)。

//本题基于208题与211题实现Trie
//为了方便,将isWordEnd由判断是否结尾改为在每个单词的最后一个字符的节点储存单词,方便在回溯过程中添加
import scala.collection.mutable

//节点定义,默认其存储“”
class Node (val children: Array[Node], var isWordEnd: String = "")

//定义Trie
class Trie {
    val root = new Node(new Array[Node](26), "")
    
    //利用word构建Trie树
    def addWord(word: String): Unit = {
        var ptr = root
        for (ch <- word) {
            if (ptr.children(ch - 'a') == null) ptr.children(ch - 'a') = new Node(new Array[Node](26), "")
            ptr = ptr.children(ch - 'a')
        }
        ptr.isWordEnd = word
    }
}


object Solution {
    //对于数组构造Trie
    def buildTrie(words: Array[String]): Trie = {
        val root = new Trie()
        for (word <- words) {
            root.addWord(word)
        }
        return root
    }
    
    def findWords(board: Array[Array[Char]], words: Array[String]): List[String] = {
        val trie = buildTrie(words)
        val rowLength = board.length
        val colLength = board.head.length
        var res = Set.empty[String]
    
        //判断位置是否正确
        def inBounds(coord: (Int, Int)): Boolean = {
            coord._1 >= 0 && coord._2 >= 0 && coord._1 < rowLength && coord._2 < colLength
        }
        
        //访问合理的四周位置
        def getNeighbors(coord: (Int, Int)): List[(Int, Int)] = {
            List(
                (coord._1 + 1, coord._2),
                (coord._1 - 1, coord._2),
                (coord._1, coord._2 + 1),
                (coord._1, coord._2 - 1)
            ).filter(inBounds(_))
        }
        
        //遍历查找
        def checkMatches(node: Node, coord: (Int, Int)): Unit = {
            val ch = board(coord._1)(coord._2)
        
			//已经访问过 返回
            if (ch == '#') return 
            
            //当前字符的节点存在
            if (node.children(ch - 'a') != null){
                val ptr = node.children(ch - 'a')
                
                //到达单词末尾
                if (ptr.isWordEnd != ""){
                    res += ptr.isWordEnd
                }
                //标记已访问
                board(coord._1)(coord._2) = '#'
                //访问四周
                for (neighbor <- getNeighbors(coord)) {
                    val letter = board(coord._1)(coord._2)
                    checkMatches(ptr, neighbor)
                }
                //回溯
                board(coord._1)(coord._2) = ch
            }
            
        }
        
        for (i <- 0 until rowLength; j <- 0 until colLength){
            checkMatches(trie.root, (i, j))
        }
        return res.toList
    }
}
posted @ 2020-09-29 23:00  ganshuoos  阅读(106)  评论(0编辑  收藏  举报