目录
- LeetCode中国站原文
- 原始题目
- 题目描述
- 示例 1:
- 示例 2:
- 示例 3:
- 提示:
- 讲解
- 化繁为简:如何优雅地“盘”逻辑判断题
- 第一部分:算法思想 —— “清单核对”与“一票否决”
- 第二部分:代码实现 —— 清晰的逻辑翻译
- 实现一:常规判断逻辑
- 实现二:使用正则表达式(一行代码的“炫技”)
- 第三部分:总结
LeetCode中国站原文
https://leetcode.cn/problems/valid-word/
原始题目
题目描述
有效单词 需要满足以下几个条件:
- 至少 包含 3 个字符。
- 由数字 0-9 和英文大小写字母组成。(不必包含所有这类字符。)
- 至少 包含一个 元音字母 。
- 至少 包含一个 辅音字母 。
给你一个字符串 word
。如果 word
是一个有效单词,则返回 true
,否则返回 false
。
注意:
'a'
、'e'
、'i'
、'o'
、'u'
及其大写形式都属于 元音字母 。- 英文中的 辅音字母 是指那些除元音字母之外的字母。
示例 1:
输入:word = "234Adas"
输出:true
解释:这个单词满足所有条件。
示例 2:
输入:word = "b3"
输出:false
解释:这个单词的长度少于 3 且没有包含元音字母。
示例 3:
输入:word = "a3$e"
输出:false
解释:这个单词包含了 '$' 字符且没有包含辅音字母。
提示:
1 <= word.length <= 20
讲解
化繁为简:如何优雅地“盘”逻辑判断题
大家好!今天我们来解决一道非常适合新手入门的题目:LeetCode 3136. 有效单词。
这道题没有炫酷的算法,也不需要复杂的数据结构。它就像一个“逻辑清单”,考验的是我们如何把一系列规则,清晰、准确地翻译成代码。这类问题在实际工作中非常常见,比如校验用户输入的密码、验证表单字段等。让我们来看看如何优雅地完成这项任务。
第一部分:算法思想 —— “清单核对”与“一票否决”
解决这类“多条件判断”问题,最好的方法就是“清单核对法”。我们可以把题目中的所有要求,想象成一张通关清单,我们的 word
字符串需要逐项检查,全部打上勾才能通关。
通关清单:
- 长度审查:
word
的长度是否>= 3
? - 成分审查:
word
中的每一个字符,是否都是字母或数字? - 元音指标:
word
中是否至少有一个元音字母? - 辅音指标:
word
中是否至少有一个辅音字母?
核心策略:“一票否决制”
在核对清单时,最有效的策略是“一票否决”。只要在检查过程中发现任何一项不满足,我们就可以立刻得出结论:这个 word
无效,直接返回 false
,后面的检查就不用再做了。这可以避免不必要的计算。
这个流程图清晰地展示了我们的策略:
- 先处理硬性条件:首先检查长度和字符合法性。这两项是“全局”的,只要有一个字符不满足,整个单词就作废。
- 再统计指标:在遍历检查字符合法性的同时,我们可以顺便完成“元音”和“辅音”的统计任务。用两个布尔变量
hasVowel
和hasConsonant
作为标记,一旦找到,就把它设为true
。 - 最后汇总:所有字符都遍历完后,如果程序还没有提前退出,说明长度和成分都合格了。这时,我们只需要检查
hasVowel
和hasConsonant
这两个标记是否都为true
,就能做出最终的裁决。
第二部分:代码实现 —— 清晰的逻辑翻译
现在,我们把“清单核对”和“一票否决”的策略翻译成代码。
实现一:常规判断逻辑
这是最直接、最易于理解的实现方式。
class Solution {/*** 校验一个字符串是否为“有效单词”。* @param word 待校验的字符串。* @return 如果有效,返回 true;否则返回 false。*/public boolean isValid(String word) {// 条件1: 长度审查if (word.length() < 3) {return false;}// 准备两个标记,用于统计元音和辅音指标boolean hasVowel = false;boolean hasConsonant = false;// 开始遍历,同时进行“成分审查”和“指标统计”for (char ch : word.toCharArray()) {// 条件2: 成分审查if (!Character.isLetterOrDigit(ch)) {return false; // 一票否-决:包含非法字符}// 判断字符类型,并更新指标if (Character.isLetter(ch)) {if ("aeiouAEIOU".indexOf(ch) != -1) {hasVowel = true; // 找到了元音} else {hasConsonant = true; // 找到了辅音}}}// 最终裁决:检查两个核心指标是否都已达成return hasVowel && hasConsonant;}
}
代码解读:
Character.isLetterOrDigit(ch)
:Java 内置的函数,非常方便地判断一个字符是否为字母或数字。"aeiouAEIOU".indexOf(ch) != -1
:这是一个判断元音的小技巧。我们把所有元音字母组成一个字符串,然后检查当前字符ch
是否能在这个字符串里找到。如果能找到(indexOf
返回的不是-1
),那它就是元音。
实现二:使用正则表达式(一行代码的“炫技”)
对于熟悉正则表达式的高手来说,可以用一行代码解决这个问题。这种方法虽然简洁,但在性能上通常不如直接遍历,且可读性对新手不友好,更适合作为一种思路扩展。
class Solution {public boolean isValid(String word) {// 正则表达式的含义:// (?=.*[aeiouAEIOU]) - 正向先行断言:字符串中必须存在至少一个元音// (?=.*[bcdfghjklmnpqrstvwxyzBCDFGHJKLMNPQRSTVWXYZ]) - 字符串中必须存在至少一个辅音// [a-zA-Z0-9]{3,} - 字符串本身必须由3个或以上的大小写字母和数字组成return word.matches("(?i)(?=.*[aeiou])(?=.*[b-df-hj-np-tv-z])[a-z0-9]{3,}");}
}
注:第二种写法为了简洁,在辅音的判断上使用了[b-df-hj-np-tv-z]
这种穷举方式,并使用 (?i)
标志来忽略大小写。这种写法主要是为了展示正则表达式的强大能力,在实际面试中,第一种清晰的遍历写法通常更受青睐。
第三部分:总结
这道“有效单词”题,是一次绝佳的编程基本功练习。它告诉我们:
- 拆解问题:面对一系列复杂规则,首先要把它们拆解成一个个清晰、独立的小任务。
- 流程控制:使用“一票否决”可以有效提升代码效率,避免不必要的计算。
- 善用工具:熟悉并使用语言内置的函数(如
Character.isLetterOrDigit
)可以让代码更简洁、更健壮。