目录

LC 792. 匹配子序列的单词数 (opens new window) (opens new window)

中等

# 问题描述

给定字符串 s 和字符串数组 words, 返回 words[i] 中是 s 的子序列的单词个数 。

字符串的 子序列 是从原始字符串中生成的新字符串,可以从中删去一些字符(可以是 none),而不改变其余字符的相对顺序。

  • 例如, “ace”“abcde” 的子序列。

示例 1:

输入: s = "abcde", words = ["a","bb","acd","ace"]
输出: 3
解释: 有三个是 s 的子序列的单词: "a", "acd", "ace"。

示例 2:

输入: s = "dsahjpjauf", words = ["ahjpjau","ja","ahbwzgqnuk","tnmlanowax"]
输出: 2

提示:

  • 1 <= s.length <= 5 * 104
  • 1 <= words.length <= 5000
  • 1 <= words[i].length <= 50
  • words[i]s 都只由小写字母组成。

# 二分查找

对字符进行预处理,记录每个字母所在的下标,然后遍历数组中的每个字符串,对于每个字母,从预处理结果中查找其下标,若该字母存在一个下标与比当前下标更大,则返回最接近的最大下标,如果该字符串能够一直找到下一个更大的下标,直到字符串遍历完毕,说明该字符串为原字符传的子序列,则否说明该字符串不为原字符串的子序列。

/**
 * @param {string} s
 * @param {string[]} words
 * @return {number}
 */
var numMatchingSubseq = function (s, words) {
  const pos = new Array(26).fill(0).map(() => [])
  for (let i = 0; i < s.length; i++) {
    pos[s.charCodeAt(i) - 97].push(i)
  }
  const binarySearch = (arr, target) => {
    if (arr.length === 0) return -1
    if (target >= arr[arr.length - 1]) return -1
    let l = 0
    let r = arr.length - 1
    while (l < r) {
      const mid = (l + r) >> 1
      if (arr[mid] <= target) {
        l = mid + 1
      } else {
        r = mid
      }
    }
    return arr[l]
  }
  let ans = words.length
  for (const word of words) {
    if (word.length <= s.length) {
      let p = -1
      for (const c of word) {
        p = binarySearch(pos[c.charCodeAt(0) - 97], p)
        if (p === -1) {
          ans--
          break
        }
      }
    }
  }
  return ans
}
  • 时间复杂度:O(n×logm)O(n \times \log{m})
  • 空间复杂度:O(n)O(n)
上次更新: 2023/01/31 19:48:05

本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 , 转载请注明出处!