今天我们开始 Leetcode 刷题,从简单的题开始,因为是随机抽到的第 58 题,那 Leetcode 刷题路就从第 58 题开始,个人能力有限,可能有些地方讲的不是很清楚,欢迎在评论区中指出,后续会做出修改。
题目
给你一个字符串 s,由若干单词组成,单词前后用一些空格字符隔开。返回字符串中 最后一个 单词的长度。
单词 是指仅由字母组成、不包含任何空格字符的最大子字符串。
示例 1:
输入:s = "Hello World"
输出:5
解释:最后一个单词是“World”,长度为5。
示例 2:
输入:s = " fly me to the moon "
输出:4
解释:最后一个单词是“moon”,长度为4。
示例 3:
输入:s = "luffy is still joyboy"
输出:6
解释:最后一个单词是长度为6的“joyboy”。
提示:
- 1 <= s.length <= 104
- s 仅有英文字母和空格
' '组成 - s 中至少存在一个单词
题解
一下属于个人的解题方法:
方式一:
根据题目中所描述:我们需要求解字符串中最后一个单词的长度,直接将整个字符串拆分为一个单词数组,然后求解最后一个单词的长度。
class Solution {
public int lengthOfLastWord(String s) {
String[] split = s.split("\\s+"); // @1
return split[split.length - 1].length();
}
}
这是最为简单的求解方式,也是大家最容易想到的。因为在多个单词之间可能存在多个空格,@1处就不能简单的以' '作为分隔符,此处正则表达式匹配1个或多个空格,这样在@1处取得的就是一个个单词,而且单词两边都是没有空格的。
提交代码:
可以看到使用这种方式求得的结果并不理想,那咱们可以换个思路。
方式二:
换一种方式,将将字符串转为字符数组,从头开始遍历,使用两个索引(i 和 j)记录最后一个单词的开始和结束位置。
class Solution {
public int lengthOfLastWord(String s) {
// 单词的开始索引的前一个位置
int i = -1;
// 单词的结束索引,最后一个有效字符的位置
int j = 0;
char[] chars = s.toCharArray();
for (int index = 0; index < chars.length; index++) {
char aChar = chars[index];
if (aChar == ' ') {
continue;
}
// 当前字符不为空,判断前一个字符是为空,遍历到了下一个单词【这是下一个单词的开始】 @
if (index - 1 >= 0 && chars[index - 1] == ' ') {
// 将下一个单词的开始索引的前一个位置赋值给 i
i = index - 1;
}
// 单词的结束位置向后移动
j = index;
}
// 遍历完后使用 结束位置 - 开始位置 得到最后一个词的长度
return j - i;
}
}
@1:判断当前字符是否是' '【空格】,是空格的话就跳过当前字符。
@2:当前字符的前一个字符是空格,此时遍历到了下一个单词的第一个字符,下一个也有可能是第一个单词的第一个有效字符,将单词的前后位置【i 和 j】后移。
当循环结束之后得到的就是最后一个单词的开始位置和结束位置。
提交代码,查看结果:
从结果中可以看到确实比第一次有了很多的进步。
方式三:
刚才我们从头开始遍历,但是题目中所要的是最后一个单词的长度,如果最后一个单词是 hello ... worle 中间省略了 n 个字符。要求的结果就在最后,但是我们却要遍历整个字符串才能得到结果,那为什么不从尾部开始向前遍历呢?
class Solution {
public int lengthOfLastWord(String s) {
char[] chars = s.toCharArray();
int length = chars.length;
int i = length; // @1
int j = length;
for (int index = length - 1; index >= 0; index--) {
char aChar = chars[index];
if (aChar == ' ') { // @2
if (j != length) { // @3
break;
}
continue;
}
if (i == length) { // @4
i = index;
}
j = index; // @5
}
return i - j + 1; // @6
}
}
@1:同样定义两个变量用于保存单词的前后位置,都给他赋初值为字符串的长度。
@2:如果字符是空格,在这就有两个可能:
- 比如字符串
s = "hello ... worle"【中间省略n个字符 】,当我们从后遍历遇见了空格,此时说明已经遍历完最后一个单词,此时就可以跳出循环。 - 比如字符串
s = "hello ... worle ..."【中间和后面省略n个字符 ,因为这里的多个空格博客上并不会都显示出来,所以我就用...代替】。我们从后开始遍历遇见的第一个字符就是空格,此时推出循环显然并不合适,此时需要判断我们是不是遍历完了一个单词。
@3:j 标注最后一个词的开始位置,当 j == length是显然还没遍历到第一个词,跳过当前字符。
@4:i == length 为 true,此时遇见了第一个有效字符,记录第一个【对于整个字符串来说应该是最后一个】有效字符的位置,i 指向的就是最后一个字符。
@5:将词的开始位置前移,j 指向的是第一个有效字符。
@6:此处 +1 的作用,这里 i 和 j 和方式二不同有些不同,j 直接指向的是第一个字符,i 指向组后一个字符,要想得到词的长度还需要 +1。
提交代码,查看结果:
从提交的结果中可以看到,无论是耗时和资源消耗方面,方式三都表现得非常优秀。
此题难度较简单,但是想要写得很好也并不容易,同样的问题不同的求解效果有千差万别,算法之美就体现得淋漓尽致。算法之路需要厚积薄发,要长时间的积累,我个人也是菜鸡中的一员,我后面也会时常提醒自己刷刷题,尽量把刷过的题都写出来。
个人能力有很多不足之处,我能写出代码但是并不一定能讲清除,请大家多多包含,无论是大家有更好的解题方法还是更好的解题过程的描述,欢迎大家在评论区中发表出来。
写到最后: 路漫漫其修远兮,吾将上下而求索。
本文详细解析LeetCode第58题“最后一个单词的长度”,提供三种解题思路及代码实现,帮助读者理解如何高效地解决问题。

372

被折叠的 条评论
为什么被折叠?



