[leetcode 刷题] 1160. 拼写单词 (javascript)

460 阅读3分钟

给你一份『词汇表』(字符串数组) words 和一张『字母表』(字符串) chars。

假如你可以用 chars 中的『字母』(字符)拼写出 words 中的某个『单词』(字符串),那么我们就认为你掌握了这个单词。

注意:每次拼写时,chars 中的每个字母都只能用一次。

返回词汇表 words 中你掌握的所有单词的 长度之和。

示例:

输入:words = ["cat","bt","hat","tree"], chars = "atach"
输出:6
解释: 
可以形成字符串 "cat""hat",所以答案是 3 + 3 = 6。

输入:words = ["hello","world","leetcode"], chars = "welldonehoneyr"
输出:10
解释:
可以形成字符串 "hello""world",所以答案是 5 + 5 = 10。

提示:

1 <= words.length <= 1000
1 <= words[i].length, chars.length <= 100
所有字符串中都仅包含小写英文字母

隐藏提示1:

Solve the problem for each string in words independently.

为每个字符串单独解决问题。

方法一:

思路

  • 针对 words 中的每个单词, 都去 chars 中查看是否拥有全部的字母
  • 将可被 chars 中拼出的字母加的一个数组(resultList)中去
  • 遍历 resultList 中的单词求得长度

代码

var countCharacters = function(words, chars) {
  // - 针对 `words` 中的每个单词, 都去 `chars` 中查看是否拥有全部的字母
  var checkWordCanBeFormed = (word, chars) => {
    let copy = chars.split('')
    for (let i = 0; i < word.length; i++) {
      var s = word[i]
      let index = copy.indexOf(s)
      if (index >= 0) {
        copy.splice(index, 1)
      } else {
        return false
      }
    }
    return true
  } 
  // - 将可被 `chars` 中拼出的字母加的一个数组(`resultList`)中去
  let resultList = []
  for (let i =0; i < words.length; i++) {
    let word = words[i]
    if (checkWordCanBeFormed(word, chars)) {
      resultList.push(word)
    }
  }
  // - 遍历 `resultList` 中的单词求得长度
  let len = 0
  resultList.forEach(word => len += word.length)
  return len
};

// countCharacters(["cat","bt","hat","tree"], "atach")
// countCharacters(["hello","world","leetcode"], "welldonehoneyr")

隐藏提示2:

Now try to think in frequency of letters.

现在尝试思考字母的频率。

隐藏提示3:

Count how many times each character occurs in string chars.

计算每个字符在字符串字符中出现的次数。

隐藏提示4:

To form a string using characters from chars, the frequency of each character in chars must be greater than or equal the frequency of that character in the string to be formed.

要使用chars中的字符形成字符串,char中每个字符的频率必须大于或等于要形成的字符串中该字符的频率。

方法二:

思路

这一部分一般来自力扣的评论区, 我会去翻一些英文站的优秀解,或优秀评论出来。

关于频率这个的理解, 我一开始以为是要得到一个字典 { h: 1, e: 1, l: 2, o: 1 } 这样子, 直到看到一个回答使用 int[26] 数组。

  • 声明一个长度为26(个英文字母)的数组
  • 遍历 chars 里面的字母 并在相应的位置 +1
  • 遍历 words 每个 word
  • 遍历每个 word 的字符 并将 int[26] 数组位置的数减一 如果该处位置的数小于0 说明不 good 如果 good res+= word.length

代码

var countCharacters = function(words, chars) {
  let res = 0
  
  const count = (chars) => {
    const root = 'a'.charCodeAt(0)
    const counter = new Array(26).fill(0)
    for (let index = 0; index < chars.length; index++) {
      counter[chars.charCodeAt(index) - root]++
    }
    return counter
  }

  const contains = (charsCount, wordCount) => {
    for (let i = 0; i < 26; i++) {
      if (charsCount[i] < wordCount[i]) {
        return false
      }
    }

    return true
  }
  
  // 统计 chars 中字母出现的频率
  const charsCount = count(chars)
  
  words.forEach(word => {
    const wordCount = count(word)

    if (contains(charsCount, wordCount)) {
      res += word.length
    }
  })

  return res
};