leetcode
leetcode 2451 ~ 2500
单词游戏

单词游戏

难度:

标签:

题目描述

代码结果

运行时间: 96 ms, 内存: 42.2 MB


/*
 * Leetcode 2868: 单词游戏
 * 
 * 题目描述:
 * 给定一个由字母和空格组成的字符串 s,返回 s 中最后一个单词的长度。
 * 如果不存在最后一个单词,请返回 0。
 * 一个单词被定义为仅由字母组成、不包含任何空格字符的最大子字符串。
 * 
 * 思路:
 * 1. 去掉字符串末尾的空格。
 * 2. 使用 Java Stream 对字符串进行反转,找到最后一个单词。
 * 3. 返回找到的单词的长度。
 */
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

public class Solution {
    public int lengthOfLastWord(String s) {
        // 去掉末尾空格
        s = s.trim();
        // 分割字符串并转换为列表
        List<String> words = Arrays.asList(s.split(" "));
        // 反转列表
        Collections.reverse(words);
        // 返回第一个单词的长度
        return words.get(0).length();
    }
}

解释

方法:

这个题解的基本思路是使用深度优先搜索(DFS)来模拟两个玩家(Alice 和 Bob)轮流从两个不同的单词列表中选择单词的游戏。玩家必须选择的单词需要字母顺序大于上一个选择的单词,并且以相邻的字母开头。解题关键是利用缓存(通过@cache装饰器)来避免重复计算相同状态下的结果,提高效率。通过递归调用`dfs`函数来判断当前玩家是否有必胜策略。如果当前玩家能选择一个单词,使得对方在下一轮没有必胜策略,则当前玩家获胜。

时间复杂度:

O(1)

空间复杂度:

O(1)

代码细节讲解

🦆
题解中提到的`字母顺序大于上一个选择的单词`是如何具体比较的?是否是比较整个字符串的字典序还是只比较首字母?
在题解中,`字母顺序大于上一个选择的单词`指的是比较两个单词的整个字符串的字典序。这意味着如果在字典中,一个单词(例如'bcd')出现在另一个单词(例如'abc')之后,则第一个单词在字典序上大于第二个单词。题解中的比较操作`left[i] > last`或`right[i] > last`就是执行这样的字典序比较,确保所选的单词在字典序上严格大于上一个选中的单词。
🦆
在函数`dfs`中,递归调用`not dfs(left[i], not flag)`返回True表示什么意思?这是如何体现当前玩家有必胜策略的?
在`dfs`函数中,`not dfs(left[i], not flag)`返回True表示如果当前玩家选择单词`left[i]`后,对手在接下来的回合中没有必胜策略。这是因为`dfs`函数设计为判断当前玩家是否会输掉游戏(即对手有必胜策略)。因此,如果对手的`dfs`调用返回False(表示对手无法必胜),那么`not dfs(...)`就会返回True,显示当前玩家通过选择这个单词能够迫使对手进入一个必败的状态。这正是体现当前玩家拥有必胜策略的关键逻辑。
🦆
题解中提到的缓存是如何优化递归性能的?能否具体解释缓存在这个问题中起到的作用和它的工作机制?
题解中使用的缓存是通过Python的`@cache`装饰器实现的,它是一种优化技术,用于存储已解决的子问题的结果。在递归过程中,某些状态可能会被重复计算多次,特别是在深度优先搜索中,这会导致效率低下。通过存储已计算过的函数结果,当相同的输入再次出现时,可以直接返回存储的结果,避免重复计算。在这个问题中,缓存存储了每个`(last, flag)`状态的结果,防止在探索不同路径时对相同的游戏状态进行重复的胜负判定。
🦆
为什么题解选择以首字母的Ascii码偏移量来初始化`left`和`right`数组?使用这种方法有什么特别的优点吗?
题解通过将首字母转换为Ascii码偏移量来初始化`left`和`right`数组,这样做可以快速定位到以特定字母开头的单词。这种方法的优点在于它提供了一种快速的索引方式,允许算法直接访问以任何特定字母开头的最大单词,而无需遍历整个单词列表。这种基于首字母索引的方式减少了查找时间,使得算法在处理大量单词时更加高效。此外,这种方法在处理字母开头的排序和比较时也更为直观和方便。

相关问题