• 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
        }
    }
    
  • 相关阅读:
    PTA习题解析——修理牧场(2 种解法)
    MySQL——维护和用户管理
    MySQL 5+ 特性
    MySQL——增、删、改
    数字时代云计算与边缘计算的区别
    5G对工业互联网应用的影响
    物联网新商业四大趋势
    变革之下,“大数据安全”成数字化转型“必答题”
    Serverless 的初心、现状和未来
    7 个建议让 Code Review 高效又高质
  • 原文地址:https://www.cnblogs.com/ganshuoos/p/13752354.html
Copyright © 2020-2023  润新知