diff --git a/solution/2000-2099/2047.Number of Valid Words in a Sentence/README.md b/solution/2000-2099/2047.Number of Valid Words in a Sentence/README.md index e1dd7c62b333f..24c1e18c1ccaa 100644 --- a/solution/2000-2099/2047.Number of Valid Words in a Sentence/README.md +++ b/solution/2000-2099/2047.Number of Valid Words in a Sentence/README.md @@ -77,7 +77,25 @@ tags: -### 方法一 +### 方法一:模拟 + +我们首先将句子按空格分割成单词,然后对每个单词进行检查,判断是否为有效单词。 + +对于每个单词,我们可以使用一个布尔变量 $\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$ 是句子的长度。 @@ -86,24 +104,23 @@ tags: ```python class Solution: def countValidWords(self, sentence: str) -> int: - def check(token): - hyphen = False - for i, c in enumerate(token): - if c.isdigit() or (c in '!.,' and i < len(token) - 1): + 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 c == "-": if ( - hyphen - or i == 0 - or i == len(token) - 1 - or not token[i - 1].islower() - or not token[i + 1].islower() + st + or i in (0, len(s) - 1) + or not s[i - 1].isalpha() + or not s[i + 1].isalpha() ): return False - hyphen = True + st = True return True - return sum(check(token) for token in sentence.split()) + return sum(check(s) for s in sentence.split()) ``` #### Java @@ -112,76 +129,142 @@ class Solution: class Solution { public int countValidWords(String sentence) { int ans = 0; - for (String token : sentence.split(" ")) { - if (check(token)) { - ++ans; - } + for (String s : sentence.split(" ")) { + ans += check(s.toCharArray()); } return ans; } - private boolean check(String token) { - int n = token.length(); - if (n == 0) { - return false; + private int check(char[] s) { + if (s.length == 0) { + return 0; } - boolean hyphen = false; - for (int i = 0; i < n; ++i) { - char c = token.charAt(i); - if (Character.isDigit(c) || (i < n - 1 && (c == '!' || c == '.' || c == ','))) { - return false; + 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 (c == '-') { - if (hyphen || i == 0 || i == n - 1 || !Character.isLetter(token.charAt(i - 1)) - || !Character.isLetter(token.charAt(i + 1))) { - return false; + if (s[i] == '-') { + if (st || i == 0 || i == s.length - 1) { + return 0; } - hyphen = true; + if (!Character.isAlphabetic(s[i - 1]) || !Character.isAlphabetic(s[i + 1])) { + return 0; + } + st = true; } } - return true; + return 1; } } ``` -#### TypeScript +#### C++ -```ts -function countValidWords(sentence: string): number { - let words = sentence.trim().split(/\s+/); - let ans = 0; - for (let word of words) { - if (isValied(word)) { - ans++; +```cpp +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; } - return ans; +}; +``` + +#### Go + +```go +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 } +``` + +#### TypeScript -function isValied(str: string): boolean { - let n = str.length; - let hasLine = false; - for (let i = 0; i < n; i++) { - const char = str.charAt(i); - if (/^[0-9]$/.test(char)) { - return false; +```ts +function countValidWords(sentence: string): number { + const check = (s: string): number => { + if (s.length === 0) { + return 0; } - if (char == '-') { - if (hasLine) return false; - else { - hasLine = true; + let st = false; + for (let i = 0; i < s.length; ++i) { + if (/\d/.test(s[i])) { + return 0; } - let pre = str.charAt(i - 1), - post = str.charAt(i + 1); - if (!/^[a-z]$/g.test(pre) || !/^[a-z]$/g.test(post)) { - return false; + 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; } } - if (/^[\!\.\,\s]$/.test(char) && i != n - 1) { - return false; - } - } - return true; + return 1; + }; + return sentence.split(/\s+/).reduce((acc, s) => acc + check(s), 0); } ``` diff --git a/solution/2000-2099/2047.Number of Valid Words in a Sentence/README_EN.md b/solution/2000-2099/2047.Number of Valid Words in a Sentence/README_EN.md index 81fc9791d496a..97a1f297178e2 100644 --- a/solution/2000-2099/2047.Number of Valid Words in a Sentence/README_EN.md +++ b/solution/2000-2099/2047.Number of Valid Words in a Sentence/README_EN.md @@ -75,7 +75,25 @@ tags: -### Solution 1 +### Solution 1: Simulation + +First, we split the sentence into words by spaces, and then check each word to determine if it is a valid word. + +For each word, we can use a boolean variable $\textit{st}$ to record whether a hyphen has already appeared, and then traverse each character in the word, judging according to the rules described in the problem. + +For each character $s[i]$, we have the following cases: + +- If $s[i]$ is a digit, then $s$ is not a valid word, and we return $\text{false}$ directly; +- If $s[i]$ is a punctuation mark ('!', '.', ','), and $i < \text{len}(s) - 1$, then $s$ is not a valid word, and we return $\text{false}$ directly; +- If $s[i]$ is a hyphen, then we need to check if the following conditions are met: + - The hyphen can only appear once; + - The hyphen cannot appear at the beginning or end of the word; + - Both sides of the hyphen must be letters; +- If $s[i]$ is a letter, then we do not need to do anything. + +Finally, we count the number of valid words in the sentence. + +The time complexity is $O(n)$, and the space complexity is $O(n)$. Here, $n$ is the length of the sentence. @@ -84,24 +102,23 @@ tags: ```python class Solution: def countValidWords(self, sentence: str) -> int: - def check(token): - hyphen = False - for i, c in enumerate(token): - if c.isdigit() or (c in '!.,' and i < len(token) - 1): + 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 c == "-": if ( - hyphen - or i == 0 - or i == len(token) - 1 - or not token[i - 1].islower() - or not token[i + 1].islower() + st + or i in (0, len(s) - 1) + or not s[i - 1].isalpha() + or not s[i + 1].isalpha() ): return False - hyphen = True + st = True return True - return sum(check(token) for token in sentence.split()) + return sum(check(s) for s in sentence.split()) ``` #### Java @@ -110,76 +127,142 @@ class Solution: class Solution { public int countValidWords(String sentence) { int ans = 0; - for (String token : sentence.split(" ")) { - if (check(token)) { - ++ans; - } + for (String s : sentence.split(" ")) { + ans += check(s.toCharArray()); } return ans; } - private boolean check(String token) { - int n = token.length(); - if (n == 0) { - return false; + private int check(char[] s) { + if (s.length == 0) { + return 0; } - boolean hyphen = false; - for (int i = 0; i < n; ++i) { - char c = token.charAt(i); - if (Character.isDigit(c) || (i < n - 1 && (c == '!' || c == '.' || c == ','))) { - return false; + 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 (c == '-') { - if (hyphen || i == 0 || i == n - 1 || !Character.isLetter(token.charAt(i - 1)) - || !Character.isLetter(token.charAt(i + 1))) { - return false; + if (s[i] == '-') { + if (st || i == 0 || i == s.length - 1) { + return 0; } - hyphen = true; + if (!Character.isAlphabetic(s[i - 1]) || !Character.isAlphabetic(s[i + 1])) { + return 0; + } + st = true; } } - return true; + return 1; } } ``` -#### TypeScript +#### C++ -```ts -function countValidWords(sentence: string): number { - let words = sentence.trim().split(/\s+/); - let ans = 0; - for (let word of words) { - if (isValied(word)) { - ans++; +```cpp +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; } - return ans; +}; +``` + +#### Go + +```go +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 } +``` + +#### TypeScript -function isValied(str: string): boolean { - let n = str.length; - let hasLine = false; - for (let i = 0; i < n; i++) { - const char = str.charAt(i); - if (/^[0-9]$/.test(char)) { - return false; +```ts +function countValidWords(sentence: string): number { + const check = (s: string): number => { + if (s.length === 0) { + return 0; } - if (char == '-') { - if (hasLine) return false; - else { - hasLine = true; + let st = false; + for (let i = 0; i < s.length; ++i) { + if (/\d/.test(s[i])) { + return 0; } - let pre = str.charAt(i - 1), - post = str.charAt(i + 1); - if (!/^[a-z]$/g.test(pre) || !/^[a-z]$/g.test(post)) { - return false; + 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; } } - if (/^[\!\.\,\s]$/.test(char) && i != n - 1) { - return false; - } - } - return true; + return 1; + }; + return sentence.split(/\s+/).reduce((acc, s) => acc + check(s), 0); } ``` diff --git a/solution/2000-2099/2047.Number of Valid Words in a Sentence/Solution.cpp b/solution/2000-2099/2047.Number of Valid Words in a Sentence/Solution.cpp new file mode 100644 index 0000000000000..03130bb72da4e --- /dev/null +++ b/solution/2000-2099/2047.Number of Valid Words in a Sentence/Solution.cpp @@ -0,0 +1,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; + } +}; diff --git a/solution/2000-2099/2047.Number of Valid Words in a Sentence/Solution.go b/solution/2000-2099/2047.Number of Valid Words in a Sentence/Solution.go new file mode 100644 index 0000000000000..f797f22162e3c --- /dev/null +++ b/solution/2000-2099/2047.Number of Valid Words in a Sentence/Solution.go @@ -0,0 +1,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 +} diff --git a/solution/2000-2099/2047.Number of Valid Words in a Sentence/Solution.java b/solution/2000-2099/2047.Number of Valid Words in a Sentence/Solution.java index 7891058179e95..3772c1674ea72 100644 --- a/solution/2000-2099/2047.Number of Valid Words in a Sentence/Solution.java +++ b/solution/2000-2099/2047.Number of Valid Words in a Sentence/Solution.java @@ -1,33 +1,34 @@ class Solution { public int countValidWords(String sentence) { int ans = 0; - for (String token : sentence.split(" ")) { - if (check(token)) { - ++ans; - } + for (String s : sentence.split(" ")) { + ans += check(s.toCharArray()); } return ans; } - private boolean check(String token) { - int n = token.length(); - if (n == 0) { - return false; + private int check(char[] s) { + if (s.length == 0) { + return 0; } - boolean hyphen = false; - for (int i = 0; i < n; ++i) { - char c = token.charAt(i); - if (Character.isDigit(c) || (i < n - 1 && (c == '!' || c == '.' || c == ','))) { - return false; + 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 (c == '-') { - if (hyphen || i == 0 || i == n - 1 || !Character.isLetter(token.charAt(i - 1)) - || !Character.isLetter(token.charAt(i + 1))) { - return false; + 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; } - hyphen = true; + st = true; } } - return true; + return 1; } -} \ No newline at end of file +} diff --git a/solution/2000-2099/2047.Number of Valid Words in a Sentence/Solution.py b/solution/2000-2099/2047.Number of Valid Words in a Sentence/Solution.py index 655d0647af88b..b30b623eb13f1 100644 --- a/solution/2000-2099/2047.Number of Valid Words in a Sentence/Solution.py +++ b/solution/2000-2099/2047.Number of Valid Words in a Sentence/Solution.py @@ -1,20 +1,19 @@ class Solution: def countValidWords(self, sentence: str) -> int: - def check(token): - hyphen = False - for i, c in enumerate(token): - if c.isdigit() or (c in '!.,' and i < len(token) - 1): + 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 c == "-": if ( - hyphen - or i == 0 - or i == len(token) - 1 - or not token[i - 1].islower() - or not token[i + 1].islower() + st + or i in (0, len(s) - 1) + or not s[i - 1].isalpha() + or not s[i + 1].isalpha() ): return False - hyphen = True + st = True return True - return sum(check(token) for token in sentence.split()) + return sum(check(s) for s in sentence.split()) diff --git a/solution/2000-2099/2047.Number of Valid Words in a Sentence/Solution.ts b/solution/2000-2099/2047.Number of Valid Words in a Sentence/Solution.ts index 67c093614a96e..0de784cbeedcf 100644 --- a/solution/2000-2099/2047.Number of Valid Words in a Sentence/Solution.ts +++ b/solution/2000-2099/2047.Number of Valid Words in a Sentence/Solution.ts @@ -1,36 +1,27 @@ function countValidWords(sentence: string): number { - let words = sentence.trim().split(/\s+/); - let ans = 0; - for (let word of words) { - if (isValied(word)) { - ans++; + const check = (s: string): number => { + if (s.length === 0) { + return 0; } - } - return ans; -} - -function isValied(str: string): boolean { - let n = str.length; - let hasLine = false; - for (let i = 0; i < n; i++) { - const char = str.charAt(i); - if (/^[0-9]$/.test(char)) { - return false; - } - if (char == '-') { - if (hasLine) return false; - else { - hasLine = true; + let st = false; + for (let i = 0; i < s.length; ++i) { + if (/\d/.test(s[i])) { + return 0; } - let pre = str.charAt(i - 1), - post = str.charAt(i + 1); - if (!/^[a-z]$/g.test(pre) || !/^[a-z]$/g.test(post)) { - return false; + 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; } } - if (/^[\!\.\,\s]$/.test(char) && i != n - 1) { - return false; - } - } - return true; + return 1; + }; + return sentence.split(/\s+/).reduce((acc, s) => acc + check(s), 0); }