【LeetCode 每日一题】3227. 字符串元音游戏
Problem: 3227. 字符串元音游戏
文章目录
- 整体思路
- 完整代码
- 时空复杂度
- 时间复杂度:O(N)
- 空间复杂度:O(1)
整体思路
这段代码旨在解决一个关于字符串和博弈论的问题。它判断的是在一个基于字符串 s
的游戏中,先手玩家 Alice 是否能获胜。
该算法的逻辑极其简单,它基于对游戏规则的一种深刻洞察,将一个看似复杂的游戏问题简化为了一个单一的条件判断。这个版本在空间使用上比使用 toCharArray()
的版本更优。
-
游戏规则的推断:
- 代码的实现表明,游戏规则很可能是:Alice 和 Bob 轮流从字符串
s
中移除一个子串。Alice 的获胜条件是她能够执行至少一次操作。 - 操作的合法性似乎与元音字母有关。一个合法的操作可能是移除一个包含至少一个元音字母的非空子串。
- 代码的实现表明,游戏规则很可能是:Alice 和 Bob 轮流从字符串
-
核心逻辑:判断是否存在元音
- 算法的思路是:如果 Alice 能够行动,她就赢了。那么,Alice 什么时候能够行动呢?——当且仅当字符串
s
中至少包含一个元音字母时。 - 如果字符串中存在元音,Alice 可以在她的第一回合,选择移除一个包含该元音的子串(例如,只包含那个元音字母本身的子串)。这样她就完成了一次操作。根据“能操作就赢”的规则,她就获胜了。
- 如果字符串中一个元音字母都没有,那么无论 Alice 选择哪个子串,该子串都不包含元音,因此她的操作是非法的。她无法进行任何操作,所以她就输了。
- 算法的思路是:如果 Alice 能够行动,她就赢了。那么,Alice 什么时候能够行动呢?——当且仅当字符串
-
算法实现:
- 基于上述逻辑,问题被简化为:检查字符串
s
中是否存在任何一个元音字母。 - 代码通过一个
for
循环和s.charAt(i)
方法来遍历字符串s
中的每一个字符c
。这种方式避免了创建字符串的副本。 - 在循环内部,它检查当前字符
c
是否是元音 ‘a’, ‘e’, ‘i’, ‘o’, ‘u’ 之一。 - 提前返回 (Early Exit):一旦找到第一个元音字母,就无需再继续检查了。此时可以确定 Alice 必胜,函数立即
return true
。 - 如果循环正常结束,说明遍历了所有字符都没有找到元音,那么 Alice 必败,函数
return false
。
- 基于上述逻辑,问题被简化为:检查字符串
完整代码
class Solution {/*** 判断在一个基于字符串的游戏中,先手 Alice 是否获胜。* @param s 输入的字符串* @return 如果 Alice 能获胜则返回 true,否则返回 false*/public boolean doesAliceWin(String s) {int n = s.length();// 遍历字符串 s 的每一个索引for (int i = 0; i < n; i++) { // 使用 charAt(i) 直接访问字符,避免创建额外的字符数组char c = s.charAt(i);// 检查当前字符 c 是否是元音if (c == 'a' || c == 'e' || c == 'i' || c == 'o' || c == 'u') {// 只要找到任何一个元音,Alice 就可以在第一回合行动并获胜。// 立即返回 true。return true;}}// 如果循环结束,说明字符串 s 中没有任何元音。// Alice 无法进行任何合法操作,因此她会失败。返回 false。return false;}
}
时空复杂度
时间复杂度:O(N)
- 循环:
for (int i = 0; i < n; i++)
循环在最坏的情况下会遍历整个字符串一次。最坏情况发生在字符串末尾才有元音,或者整个字符串都没有元音。 - 循环内部操作:
s.charAt(i)
在 Java 中是 O(1) 操作,后续的比较也是 O(1) 的。
综合分析:
算法的总时间复杂度由线性扫描决定。因此,其时间复杂度为 O(N),其中 N
是字符串 s
的长度。
空间复杂度:O(1)
- 主要存储开销:该实现只使用了几个基本类型的变量(
n
,i
,c
)。 - 空间大小:这些变量的数量是固定的,不随输入字符串
s
的长度N
而改变。 - 与
toCharArray()
的对比:与使用s.toCharArray()
的版本不同,此版本不创建字符串的任何副本。s.charAt(i)
直接访问字符串内部的字符存储,因此没有 O(N) 的额外空间开销。
综合分析:
算法所需的额外辅助空间是常数级别的。因此,其空间复杂度为 O(1)。