跳转至

2047. 句子中的有效单词数

题目描述

句子仅由小写字母('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" 不是有效单词,因为它含有数字

 

提示:

  • 1 <= sentence.length <= 1000
  • sentence 由小写英文字母、数字(0-9)、以及字符(' ''-''!''.'',')组成
  • 句子中至少有 1 个 token

解法

方法一:模拟

我们首先将句子按空格分割成单词,然后对每个单词进行检查,判断是否为有效单词。

对于每个单词,我们可以使用一个布尔变量 $\textit{st}$ 来记录是否已经出现过连字符,然后遍历单词中的每个字符,根据题目描述的规则进行判断。

对于每个字符 $s[i]$,我们有以下几种情况:

  • 如果 $s[i]$ 是数字,那么 $s$ 不是有效单词,直接返回 $\text{false}$;
  • 如果 $s[i]$ 是标点符号('!'、'.'、',')且 $i < \text{len}(s) - 1$,那么 $s$ 不是有效单词,直接返回 $\text{false}$;
  • 如果 $s[i]$ 是连字符,那么我们需要判断是否满足以下条件:
    • 连字符只能出现一次;
    • 连字符不能出现在单词的开头或结尾;
    • 连字符两侧必须是字母;
  • 如果 $s[i]$ 是字母,那么我们不需要做任何处理。

最后,我们统计出句子中的有效单词数即可。

时间复杂度 $O(n)$,空间复杂度 $O(n)$。其中 $n$ 是句子的长度。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
class Solution:
    def countValidWords(self, sentence: str) -> int:
        def check(s: str) -> bool:
            st = False
            for i, c in enumerate(s):
                if c.isdigit() or (c in "!.," and i < len(s) - 1):
                    return False
                if c == "-":
                    if (
                        st
                        or i in (0, len(s) - 1)
                        or not s[i - 1].isalpha()
                        or not s[i + 1].isalpha()
                    ):
                        return False
                    st = True
            return True

        return sum(check(s) for s in sentence.split())
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
class Solution {
    public int countValidWords(String sentence) {
        int ans = 0;
        for (String s : sentence.split(" ")) {
            ans += check(s.toCharArray());
        }
        return ans;
    }

    private int check(char[] s) {
        if (s.length == 0) {
            return 0;
        }
        boolean st = false;
        for (int i = 0; i < s.length; ++i) {
            if (Character.isDigit(s[i])) {
                return 0;
            }
            if ((s[i] == '!' || s[i] == '.' || s[i] == ',') && i < s.length - 1) {
                return 0;
            }
            if (s[i] == '-') {
                if (st || i == 0 || i == s.length - 1) {
                    return 0;
                }
                if (!Character.isAlphabetic(s[i - 1]) || !Character.isAlphabetic(s[i + 1])) {
                    return 0;
                }
                st = true;
            }
        }
        return 1;
    }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
class Solution {
public:
    int countValidWords(string sentence) {
        auto check = [](const string& s) -> int {
            bool st = false;
            for (int i = 0; i < s.length(); ++i) {
                if (isdigit(s[i])) {
                    return 0;
                }
                if ((s[i] == '!' || s[i] == '.' || s[i] == ',') && i < s.length() - 1) {
                    return 0;
                }
                if (s[i] == '-') {
                    if (st || i == 0 || i == s.length() - 1) {
                        return 0;
                    }
                    if (!isalpha(s[i - 1]) || !isalpha(s[i + 1])) {
                        return 0;
                    }
                    st = true;
                }
            }
            return 1;
        };

        int ans = 0;
        stringstream ss(sentence);
        string s;
        while (ss >> s) {
            ans += check(s);
        }
        return ans;
    }
};
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
func countValidWords(sentence string) (ans int) {
    check := func(s string) int {
        if len(s) == 0 {
            return 0
        }
        st := false
        for i, r := range s {
            if unicode.IsDigit(r) {
                return 0
            }
            if (r == '!' || r == '.' || r == ',') && i < len(s)-1 {
                return 0
            }
            if r == '-' {
                if st || i == 0 || i == len(s)-1 {
                    return 0
                }
                if !unicode.IsLetter(rune(s[i-1])) || !unicode.IsLetter(rune(s[i+1])) {
                    return 0
                }
                st = true
            }
        }
        return 1
    }
    for _, s := range strings.Fields(sentence) {
        ans += check(s)
    }
    return ans
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
function countValidWords(sentence: string): number {
    const check = (s: string): number => {
        if (s.length === 0) {
            return 0;
        }
        let st = false;
        for (let i = 0; i < s.length; ++i) {
            if (/\d/.test(s[i])) {
                return 0;
            }
            if (['!', '.', ','].includes(s[i]) && i < s.length - 1) {
                return 0;
            }
            if (s[i] === '-') {
                if (st || [0, s.length - 1].includes(i)) {
                    return 0;
                }
                if (!/[a-zA-Z]/.test(s[i - 1]) || !/[a-zA-Z]/.test(s[i + 1])) {
                    return 0;
                }
                st = true;
            }
        }
        return 1;
    };
    return sentence.split(/\s+/).reduce((acc, s) => acc + check(s), 0);
}

评论