力扣每日一题0127-2047. 句子中的有效单词数

170 阅读2分钟

「这是我参与2022首次更文挑战的第6天,活动详情查看:2022首次更文挑战」。

句子仅由小写字母('a''z')、数字('0''9')、连字符('-')、标点符号('!''.'',')以及空格(' ')组成。每个句子可以根据空格分解成 一个或者多个 token ,这些 token 之间由一个或者多个空格 ' ' 分隔。

如果一个 token 同时满足下述条件,则认为这个 token 是一个有效单词:

  • 仅由小写字母、连字符和/或标点(不含数字)。
  • 至多一个 连字符 '-' 。如果存在,连字符两侧应当都存在小写字母("a-b" 是一个有效单词,但 "-ab""ab-" 不是有效单词)。
  • 至多一个 标点符号。如果存在,标点符号应当位于 token 的 末尾

这里给出几个有效单词的例子:"a-b.""afad""ba-c""a!""!"

给你一个字符串 sentence ,请你找出并返回 **sentence有效单词的数目

示例 1:

输入:sentence = "cat and  dog"
输出:3
解释:句子中的有效单词是 "cat""and""dog"

示例 2:

输入:sentence = "!this  1-s b8d!"
输出:0
解释:句子中没有有效单词
"!this" 不是有效单词,因为它以一个标点开头
"1-s""b8d" 也不是有效单词,因为它们都包含数字

示例 3:

输入:sentence = "alice and  bob are playing stone-game10"
输出:5
解释:句子中的有效单词是 "alice""and""bob""are""playing"
"stone-game10" 不是有效单词,因为它含有数字

示例 4:

输入:sentence = "he bought 2 pencils, 3 erasers, and 1  pencil-sharpener."
输出:6
解释:句子中的有效单词是 "he""bought""pencils,""erasers,""and""pencil-sharpener."

遍历

这道题我们需要直接遍历,我们先找到有多少个token。我们需要通过空格将token分开

const arr = sentence.split(" ")

这样我们就得到了一个或者多个 token ,但是稍后判断的时候我们还需要判断是否为空,因为当多个token中间是两个空格时,这种方法就会将一个空格判断为符合条件。

然后我们就需要根据条件判断,每一个token是否符合条件。

  • 仅由小写字母、连字符和/或标点(不含数字)。

所以我们要判断token是否含有数字

我们遍历每一个token得到

for(let i =0;i<token.length;i++){
	if(token[i]>="0"&&token[i]<="9") return false
}
  • 至多一个 连字符 '-' 。如果存在,连字符两侧应当都存在小写字母("a-b" 是一个有效单词,但 "-ab""ab-" 不是有效单词)。

根据第二个条件,只允许有至多一个的“-”,并且必须在字符中间,也就是说多余一个,或者在头在尾都不成立。

let hasHyphens = false;
if (word[i] === '-') {
	if (hasHyphens === true || i === 0 || i === n - 1 || !isLetter(word[i - 1]) || !isLetter(word[i + 1])) {
	return false;
}

其中的isLetter判断是否为字母。

const isLetter = (ch) => {
  if (ch >= 'a' && ch <= 'z' || ch >= 'A' && ch <= 'Z') {
    return true;
  }
  return false;
}
  • 至多一个 标点符号。如果存在,标点符号应当位于 token 的 末尾

最后就是是否有标点符号,有必须在结尾。

if (word[i] === '!' || word[i] === '.' || word[i] === ',') {
	if (i !== n - 1) {
		return false;
	}
}

当出现了上述的标点符号时,必须在结尾。

总结起来就是

var countValidWords = function (sentence) {
  const arr = sentence.split(" ")
  const len = arr.length
  let ans = 0

  for (const a of arr) {
    if (isValid(a)) ans++
  }
  return ans
  function isValid (word) {
    const n = word.length;
    let hasHyphens = false;
    for (let i = 0; i < n; i++) {
      if (word[i] >= '0' && word[i] <= '9') {
        return false;
      } else if (word[i] === '-') {
        if (hasHyphens === true || i === 0 || i === n - 1 || !isLetter(word[i - 1]) || !isLetter(word[i + 1])) {
          return false;
        }
        hasHyphens = true;
      } else if (word[i] === '!' || word[i] === '.' || word[i] === ',') {
        if (i !== n - 1) {
          return false;
        }
      }
    }
    return true;
  }
};

const isLetter = (ch) => {
  if (ch >= 'a' && ch <= 'z' || ch >= 'A' && ch <= 'Z') {
    return true;
  }
  return false;
}

image.png

正则表达式

我们再来看一下所需条件

  • 没有数字
  • “-”前后都是字母
  • 标点出现在最后
/^([,.!]|[a-z]+(-[a-z]+)?[,.!]?)$/

|表示也有可能一个token只有标点符号的可能。

var countValidWords = function (sentence) {
  return sentence.split(' ').filter(w => /^([,.!]|[a-z]+(-[a-z]+)?[,.!]?)$/.test(w)).length;
};

image.png