Golang每日一练(leetDay0074) 词典类设计、单词搜索II

简介: Golang每日一练(leetDay0074) 词典类设计、单词搜索II

211. 添加与搜索单词 - 数据结构设计 Design-add-and-search-words-data-structure


请你设计一个数据结构,支持 添加新单词 和 查找字符串是否与任何先前添加的字符串匹配 。


实现词典类 WordDictionary


   WordDictionary() 初始化词典对象

   void addWord(word) 将 word 添加到数据结构中,之后可以对它进行匹配

   bool search(word) 如果数据结构中存在字符串与 word 匹配,则返回 true ;否则,返回  false 。word 中可能包含一些 '.' ,每个 . 都可以表示任何一个字母。


示例:


输入:
["WordDictionary","addWord","addWord","addWord","search","search","search","search"]
[[],["bad"],["dad"],["mad"],["pad"],["bad"],[".ad"],["b.."]]
输出:
[null,null,null,null,false,true,true,true]
解释:
WordDictionary wordDictionary = new WordDictionary();
wordDictionary.addWord("bad");
wordDictionary.addWord("dad");
wordDictionary.addWord("mad");
wordDictionary.search("pad"); // 返回 False
wordDictionary.search("bad"); // 返回 True
wordDictionary.search(".ad"); // 返回 True
wordDictionary.search("b.."); // 返回 True


提示:

  • 1 <= word.length <= 25
  • addWord 中的 word 由小写英文字母组成
  • search 中的 word 由 '.' 或小写英文字母组成
  • 最多调用 10^4addWordsearch

代码:

package main
import "fmt"
type TrieNode struct {
  children [26]*TrieNode
  isWord   bool
}
type WordDictionary struct {
  root *TrieNode
}
func Constructor() WordDictionary {
  return WordDictionary{root: &TrieNode{}}
}
func (this *WordDictionary) AddWord(word string) {
  node := this.root
  for _, ch := range word {
    idx := ch - 'a'
    if node.children[idx] == nil {
      node.children[idx] = &TrieNode{}
    }
    node = node.children[idx]
  }
  node.isWord = true
}
func (this *WordDictionary) Search(word string) bool {
  return this.match(this.root, word, 0)
}
func (this *WordDictionary) match(node *TrieNode, word string, idx int) bool {
  if node == nil {
    return false
  }
  if idx == len(word) {
    return node.isWord
  }
  ch := word[idx]
  if ch != '.' {
    child := node.children[ch-'a']
    if child != nil && this.match(child, word, idx+1) {
      return true
    }
  } else {
    for _, child := range node.children {
      if child != nil && this.match(child, word, idx+1) {
        return true
      }
    }
  }
  return false
}
func main() {
  wordDictionary := Constructor()
  wordDictionary.AddWord("bad")
  wordDictionary.AddWord("dad")
  wordDictionary.AddWord("mad")
  fmt.Println(wordDictionary.Search("pad"))
  fmt.Println(wordDictionary.Search("bad"))
  fmt.Println(wordDictionary.Search(".ad"))
  fmt.Println(wordDictionary.Search("b.."))
}

输出:

false

true

true

true


212. 单词搜索 II Word Search ii


给定一个 m x n 二维字符网格 board 和一个单词(字符串)列表 words, 返回所有二维网格上的单词 。


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


示例 1:

616b64d602fe27993a16895c4e1ea4cf.jpeg


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

输出:["eat","oath"]


示例 2:

439e8ca586140b713033cc5af14b2d08.jpeg

输入:board = [["a","b"],["c","d"]], words = ["abcb"]

输出:[]

提示:

   m == board.length

   n == board[i].length

   1 <= m, n <= 12

   board[i][j] 是一个小写英文字母

   1 <= words.length <= 3 * 10^4

   1 <= words[i].length <= 10

   words[i] 由小写英文字母组成

   words 中的所有字符串互不相同


相关题目:  单词搜索 I Word Search i


https://hannyang.blog.csdn.net/article/details/129971403#t0

代码1: 哈希表 + dfs

package main
import "fmt"
type entry struct {
  row, col int
}
func findWords(board [][]byte, words []string) []string {
  n, m := len(board), len(board[0])
  wordIndex := make(map[string]int)
  for i, word := range words {
    wordIndex[word] = i
  }
  visited := make([][]bool, n)
  for i := range visited {
    visited[i] = make([]bool, m)
  }
  dirs := []entry{{-1, 0}, {1, 0}, {0, -1}, {0, 1}}
  var res []string
  var dfs func(string, int, int)
  dfs = func(cur string, i, j int) {
    if idx, ok := wordIndex[cur]; ok {
      res = append(res, words[idx])
      delete(wordIndex, cur)
    }
    for _, dir := range dirs {
      ni, nj := i+dir.row, j+dir.col
      if ni < 0 || ni >= n || nj < 0 || nj >= m || visited[ni][nj] {
        continue
      }
      visited[ni][nj] = true
      dfs(cur+string(board[ni][nj]), ni, nj)
      visited[ni][nj] = false
    }
  }
  for i := 0; i < n; i++ {
    for j := 0; j < m; j++ {
      visited[i][j] = true
      dfs(string(board[i][j]), i, j)
      visited[i][j] = false
    }
  }
  return res
}
func main() {
  board := [][]byte{{'o', 'a', 'a', 'n'}, {'e', 't', 'a', 'e'}, {'i', 'h', 'k', 'r'}, {'i', 'f', 'l', 'v'}}
  words := []string{"oath", "pea", "eat", "rain"}
  fmt.Println(findWords(board, words))
}


代码2: 前缀树 Trie

package main
import "fmt"
type TrieNode struct {
  ch       byte
  children [26]*TrieNode
  word     string
}
type Trie struct {
  root *TrieNode
}
func NewTrie() *Trie {
  return &Trie{root: &TrieNode{}}
}
func (t *Trie) Insert(word string) {
  node := t.root
  for i := 0; i < len(word); i++ {
    ch := word[i]
    if idx := ch - 'a'; idx >= 0 && idx < 26 {
      if node.children[idx] == nil {
        node.children[idx] = &TrieNode{ch: ch}
      }
      node = node.children[idx]
    } else {
      return
    }
  }
  node.word = word
}
func findWords(board [][]byte, words []string) []string {
  trie := NewTrie()
  for _, word := range words {
    trie.Insert(word)
  }
  visited := make([][]bool, len(board))
  for i := 0; i < len(board); i++ {
    visited[i] = make([]bool, len(board[0]))
  }
  var res []string
  var dfs func(node *TrieNode, i, j int)
  dfs = func(node *TrieNode, i, j int) {
    if node.word != "" {
      res = append(res, node.word)
      node.word = "" // 避免重复添加
    }
    if i < 0 || i >= len(board) || j < 0 || j >= len(board[0]) {
      return
    }
    if visited[i][j] || node.children[board[i][j]-'a'] == nil {
      return
    }
    visited[i][j] = true
    idx := board[i][j] - 'a'
    child := node.children[idx]
    dfs(child, i-1, j)
    dfs(child, i+1, j)
    dfs(child, i, j-1)
    dfs(child, i, j+1)
    visited[i][j] = false
  }
  for i := 0; i < len(board); i++ {
    for j := 0; j < len(board[0]); j++ {
      dfs(trie.root, i, j)
    }
  }
  return res
}
func main() {
  board := [][]byte{{'o', 'a', 'a', 'n'}, {'e', 't', 'a', 'e'}, {'i', 'h', 'k', 'r'}, {'i', 'f', 'l', 'v'}}
  words := []string{"oath", "pea", "eat", "rain"}
  fmt.Println(findWords(board, words))
}

输出:

[oath eat]

目录
相关文章
|
4月前
|
Shell Linux 算法
Shell编程——弱数据类型的脚本语言快速入门指南
Shell编程——弱数据类型的脚本语言快速入门指南
57 0
Shell编程——弱数据类型的脚本语言快速入门指南
|
4月前
|
Go Linux Shell
Linux 终端命令之文件浏览(2) more
Linux 终端命令之文件浏览(2) more
32 0
Linux 终端命令之文件浏览(2) more
|
4月前
|
Shell 机器学习/深度学习 Linux
Linux 终端操作命令(2)内部命令
Linux 终端操作命令(2)内部命令
21 0
Linux 终端操作命令(2)内部命令
|
4月前
|
C++ 算法 存储
力扣 C++|一题多解之动态规划专题(2)
力扣 C++|一题多解之动态规划专题(2)
39 0
力扣 C++|一题多解之动态规划专题(2)
|
4月前
|
Python 索引
Python Numpy入门基础(一)创建数组
Python Numpy入门基础(一)创建数组
40 0
Python Numpy入门基础(一)创建数组
|
4月前
|
Java 容器 程序员
Java语言程序设计试卷6套
Java语言程序设计试卷6套
135 0
Java语言程序设计试卷6套
|
20小时前
|
前端开发 Go
Golang深入浅出之-Go语言中的异步编程与Future/Promise模式
【5月更文挑战第3天】Go语言通过goroutines和channels实现异步编程,虽无内置Future/Promise,但可借助其特性模拟。本文探讨了如何使用channel实现Future模式,提供了异步获取URL内容长度的示例,并警示了Channel泄漏、错误处理和并发控制等常见问题。为避免这些问题,建议显式关闭channel、使用context.Context、并发控制机制及有效传播错误。理解并应用这些技巧能提升Go语言异步编程的效率和健壮性。
7 5
Golang深入浅出之-Go语言中的异步编程与Future/Promise模式
|
20小时前
|
监控 负载均衡 算法
Golang深入浅出之-Go语言中的协程池设计与实现
【5月更文挑战第3天】本文探讨了Go语言中的协程池设计,用于管理goroutine并优化并发性能。协程池通过限制同时运行的goroutine数量防止资源耗尽,包括任务队列和工作协程两部分。基本实现思路涉及使用channel作为任务队列,固定数量的工作协程处理任务。文章还列举了一个简单的协程池实现示例,并讨论了常见问题如任务队列溢出、协程泄露和任务调度不均,提出了解决方案。通过合理设置缓冲区大小、确保资源释放、优化任务调度以及监控与调试,可以避免这些问题,提升系统性能和稳定性。
8 5
|
20小时前
|
安全 Go
Golang深入浅出之-Go语言中的并发安全队列:实现与应用
【5月更文挑战第3天】本文探讨了Go语言中的并发安全队列,它是构建高性能并发系统的基础。文章介绍了两种实现方法:1) 使用`sync.Mutex`保护的简单队列,通过加锁解锁确保数据一致性;2) 使用通道(Channel)实现无锁队列,天生并发安全。同时,文中列举了并发编程中常见的死锁、数据竞争和通道阻塞问题,并给出了避免这些问题的策略,如明确锁边界、使用带缓冲通道、优雅处理关闭以及利用Go标准库。
8 5
|
1天前
|
存储 缓存 安全
Golang深入浅出之-Go语言中的并发安全容器:sync.Map与sync.Pool
Go语言中的`sync.Map`和`sync.Pool`是并发安全的容器。`sync.Map`提供并发安全的键值对存储,适合快速读取和少写入的情况。注意不要直接遍历Map,应使用`Range`方法。`sync.Pool`是对象池,用于缓存可重用对象,减少内存分配。使用时需注意对象生命周期管理和容量控制。在多goroutine环境下,这两个容器能提高性能和稳定性,但需根据场景谨慎使用,避免不当操作导致的问题。
14 4