leetcode-每日一题745. 前缀和后缀搜索(哈希和字典树)

简介: 如果我们用前缀 prefix 和 后缀 suff去暴力对比所有单词肯定会超时,我们可以先把单词里所有的前缀后缀组合,中间用特殊符号@连接,对应的最大下标存入哈希表中。搜索时,用特殊符号@连接前缀后缀,在哈希表中进行搜索

259240b0884f4f6a91e834ba9e66067a.png


题目链接:https://leetcode.cn/problems/prefix-and-suffix-search/

思路


方法一、用哈希表记录每个单词的前缀和后缀组合


直接想法

如果我们用前缀 prefix 和 后缀 suff去暴力对比所有单词肯定会超时,我们可以先把单词里所有的前缀后缀组合,中间用特殊符号@连接,对应的最大下标存入哈希表中。搜索时,用特殊符号@连接前缀后缀,在哈希表中进行搜索


算法


1.把WordFilter类自定义为 map[string]int, 用于所有的前缀后缀组合的最大下标


2.Constructor函数 遍历所有单词,把单词里所有的前缀后缀组合,中间用特殊符号@连接,对应的最大下标存入哈希表WordFilter中


3.F方法用来判断前缀+ @ +后缀的组合是否存在于哈希表中


代码示例


type WordFilter map[string]int
func Constructor(words []string) WordFilter {
   wf := WordFilter{}
   for i := range words{
       for j, n := 1, len(words[i]); j <= n; j++{
           for k := 0; k < n; k++{
               wf[words[i][:j] + "@" + words[i][k:]] = i
           }
       }
   }
   return wf
}
func (wf WordFilter) F(pref, suff string) int {
    if i, ok := wf[pref + "@" + suff]; ok{
        return i
    }
    return -1
}

577aa4bbdbbc4f96972e909b8f14e6bc.png


复杂度分析


f2824e20067b4aabbec3f61c38e17155.png


方法二、字典树


直接想法


这道题首先想到的就是构造前缀、后缀字典树。其中树节点储存包含此前(后)缀的单词索引。在后续调用F方法时,一次遍历前后缀字典树,找到满足要求的前后缀单词索引集合,然后找出两个集合中最大的相同值,即为题解。


算法


1.构造前缀、后缀字典树


2.Constructor函数 把所有单词的前缀、后缀下标存入当前前缀字典树和后缀字典树结点的idx数组


3.F方法通过找到pref在前缀字典树的结点和suff在后缀字典树的结点,找到两个结点中idx数组中相同的最大下标输出


代码示例


type trie struct {
    next []*trie
    idx []int
}
type WordFilter struct {
    pref,suff []*trie
}
func Constructor(words []string) WordFilter {
    pref, suff := make([]*trie, 26), make([]*trie, 26)
  for i, word := range words {
    pf, sf, n := pref, suff, len(word)
    for x, y := 0, n - 1; x < n && y >= 0; x, y = x + 1, y - 1 {
            //构造前缀,把所有单词前缀组合下标在当前前缀字典树结点idx数组里
      a := int(word[x] - 'a')
      if pf[a] == nil {
        pf[a] = &trie{
          next: make([]*trie, 26),
          idx:  []int{i},
        }
      } else {
        pf[a].idx = append(pf[a].idx, i)
      }
      pf = pf[a].next
            //构造后缀,把所有单词后缀组合下标在当前后缀字典树结点idx数组里
            a = int(word[y] - 'a')
      if sf[a] == nil {
        sf[a] = &trie{next: make([]*trie, 26), idx: []int{i}}
      } else {
        sf[a].idx = append(sf[a].idx, i)
      }
      sf = sf[a].next
    }
  }
  return WordFilter{pref: pref, suff: suff}
}
func (this *WordFilter) F(pref string, suff string) int {
      p := this.pref
  var prefCandicates, suffCandicates []int
  for i := range pref {
    c := int(pref[i] - 'a')
    if p[c] == nil {
      return -1
    }
    //完全匹配前缀
    if i == len(pref)-1 {
      prefCandicates = p[c].idx
    }
    p = p[c].next
  }
  q := this.suff
  for i := len(suff) - 1; i >= 0; i-- {
    c := int(suff[i] - 'a')
    if q[c] == nil {
      return -1
    }
    //完全匹配后缀
    if i == 0 {
      suffCandicates = q[c].idx
    }
    q = q[c].next
  }
  i, j := len(prefCandicates)-1, len(suffCandicates)-1
  for i > -1 && j > -1 {
    //前缀和后缀存在于一个单词
    if prefCandicates[i] == suffCandicates[j] {
      return prefCandicates[i]
    }
    //尽量找到最大下标
    if prefCandicates[i] < suffCandicates[j] {
      j--
    } else {
      i--
    }
  }
  return -1
}

6cb21ad1967a42d6b86949ac1fc37ad2.png


复杂度分析


49a2bf96bfe943d78d1d9d800e2cbdd0.png

目录
相关文章
|
1月前
|
算法
LeetCode第81题搜索旋转排序数组 II
文章讲解了LeetCode第81题"搜索旋转排序数组 II"的解法,通过二分查找算法并加入去重逻辑来解决在旋转且含有重复元素的数组中搜索特定值的问题。
LeetCode第81题搜索旋转排序数组 II
|
1月前
|
算法
LeetCode第74题搜索二维矩阵
文章讲解了LeetCode第74题"搜索二维矩阵"的解决方案,利用二分搜索法将问题简化,并通过数学转换找到二维矩阵中的对应元素,展示了将二维问题转化为一维问题的解题技巧。
LeetCode第74题搜索二维矩阵
|
1月前
|
算法
LeetCode第35题搜索插入位置
这篇文章介绍了LeetCode第35题"搜索插入位置"的解题方法,通过使用二分查找法,高效地找到在有序数组中插入一个目标数的最佳位置。
LeetCode第35题搜索插入位置
|
1月前
|
算法
LeetCode第33题搜索旋转排序数组
这篇文章介绍了LeetCode第33题"搜索旋转排序数组"的解题方法,通过使用二分查找法并根据数组的有序性质调整搜索范围,实现了时间复杂度为O(log n)的高效搜索算法。
LeetCode第33题搜索旋转排序数组
|
1月前
|
算法 JavaScript Python
【Leetcode刷题Python】79. 单词搜索和剑指 Offer 12. 矩阵中的路径
Leetcode第79题"单词搜索"的Python解决方案,使用回溯算法在给定的二维字符网格中搜索单词,判断单词是否存在于网格中。
23 4
|
1月前
|
算法 Python
【Leetcode刷题Python】74. 搜索二维矩阵
两种解决LeetCode "搜索二维矩阵" 问题的方法的Python实现。第一种方法是从二维矩阵的右上角开始线性搜索,通过比较当前元素与目标值来决定搜索方向。第二种方法是将二维矩阵视为一维数组进行二分查找,通过计算中间元素的行列索引来更新搜索区间。两种方法都旨在高效地判断目标值是否存在于给定的有序二维矩阵中。
23 0
|
1月前
|
算法 索引 Python
【Leetcode刷题Python】33. 搜索旋转排序数组
解决LeetCode "搜索旋转排序数组" 问题的Python实现代码。代码使用了二分查找算法,首先检查目标值是否存在于数组中,然后通过比较数组中间值与数组首尾值来确定应该在数组的哪一半继续搜索,直到找到目标值或搜索范围为空。如果找到目标值,返回其索引;如果搜索结束仍未找到,返回 -1。
13 0
|
1月前
|
索引 Python
【Leetcode刷题Python】35. 搜索插入位置
解决在排序数组中查找目标值并返回其索引或插入位置的问题的Python实现代码。
16 0
|
3月前
力扣每日一题 6/11 暴力搜索
力扣每日一题 6/11 暴力搜索
16 0
|
3月前
【LeetCode刷题】前缀和解决问题:742.寻找数组的中心下标、238.除自身以外数组的乘积
【LeetCode刷题】前缀和解决问题:742.寻找数组的中心下标、238.除自身以外数组的乘积