# 58. 最后一个单词的长度 (opens new window)
# 题目描述
给你一个字符串 s,由若干单词组成,单词之间用空格隔开。返回字符串中最后一个单词的长度。如果不存在最后一个单词,请返回 0 。 单词 是指仅由字母组成、不包含任何空格字符的最大子字符串。
示例 1:
输入:s = "Hello World"
输出:5
示例 2:
输入:s = " "
输出:0
提示: 1 <= s.length <= 104 s 仅有英文字母和空格 ' ' 组成
相关信息:
- 难度:简单
- 标签:字符串
# 题解
本题是名副其实的简单题,作为老 API 调用怪,我直接几个 API 一把梭就搞定了,很快啊~嘿嘿,好了,不皮了。本题主要需要处理的情况有三种:
"Hello Word"
:这是比较正常的情况,最后的位置存在单词。"Hello Word "
:这种情况就是以空格结尾,但是空格之前有单词存在,所以Word
应该是它的最后一个单词,这一点在题目的描述中表述得不是很清楚。" "
:这种情况就是纯的空字符串,直接返回零 0⃣️。
# 方法一:双指针
首先,我们从最原始的写法开始吧,然后一步步用 API 替代。
第一种实现思路,尾部指针从尾部开始,忽略尾部空格,指向尾部第一个非空格字符,然后头部指针从尾部出发,一直移动,直到遇见第一个空字符。返回尾部指针和头部指针之间的差值,即为单词长度。
/**
执行用时: 84 ms
内存消耗: 37.6 MB
*/
var lengthOfLastWord = function (s) {
let end = s.length - 1; //尾部指针
while (end >= 0 && s[end] == " ") end--; //忽略尾部空格
if (end < 0) return 0;
let start = end; //头部指针出发
while (start >= 0 && s[start] != " ") start--;
return end - start;
};
上边这种实现方式不太好的是使用了两次循环,不过一般尾部空格不会太多,所以实际影响也还好。
第二种实现方式就是将两次循环压缩到了一次循环,直接从尾部向头部循环一次,从第一个非空格字符开始计数,一旦再次遇到空格便结束循环。
/**
执行用时: 72 ms
内存消耗: 37.6 MB
*/
var lengthOfLastWord = function (s) {
let count = 0;
for (let i = s.length - 1; i > -1; i--) {
if (s[i] === " ") {
if (count == 0) continue; //count为零时便一直跳过末尾的空字符
break; //count非零之后,第二次遇到空字符就结束
}
count++;
}
return count;
};
从结果可以看出,这种实现方法确实有所提升。
另外,有同学会在函数体首部单独判断 s===' ',然后直接返回 0;我个人认为没有这个必要,因为所有遍历都是从尾部开始的,空字符串相比其他状况已经缩减了许多步骤,相比于直接返回 0,并没有多处太多处理时间。经过我实际测试,弃掉这个判断,函数运行速度反而提升了,非常玄学。总之后,并非所有特殊情况,在函数体首部单独判断处理之后都能提升大幅度提升运行速率,应视具体情况而定。
# 方法二:开启 API 大赏
# filter+split
/**
执行用时: 64 ms
内存消耗: 37.7 MB
*/
var lengthOfLastWord = function (s) {
//分割后空数组全部筛去
let words = s.split(" ").filter((item) => item != "");
//注意如果原数组全部为空格,筛选后words为空数组
return words.length != 0 ? words[words.length - 1].length : 0;
};
# trim+split+reserve
/*
执行用时: 76 ms
内存消耗: 38.1 MB
*/
//这样反转数组还是比较耗时耗空间的
var lengthOfLastWord = function (s) {
return s.trim().split(" ").reverse()[0].length;
//trim 去除首尾空格;split 按空格分割,reverse 反转数组。
};
# trim + split+pop
/*
执行用时: 108 ms
内存消耗: 37.7 MB
*/
//果然开启API之后,运行速度会降很多,但我认为这是我目前想到的最简单的写法
var lengthOfLastWord = function (s) {
return s.trim().split(" ").pop().length;
//trim 去除首尾空格;split 按空格分割,pop弹出尾部单词
};
以上就是本题的所有题解啦,感谢你能看到这里,如果本文对你有所帮助的话,别忘了给一个 Star 嗷~ 如果你对题解中的代码有不一样的优化意见,也欢迎你在 issue 中指出~ 最重要的是不要忘了点点关注嗷(Github (opens new window)、力扣 (opens new window)),以便获取我最新的题解以及文章通知。
# 参考文章:
- 画解算法:58. 最后一个单词的长度 (opens new window)
- JS 一行代码两种方法 时间超过 85% (opens new window)
- 用 filter 啊 (opens new window)
# 全部代码
/*
* @lc app=leetcode.cn id=58 lang=javascript
*
* [58] 最后一个单词的长度
*
* https://leetcode-cn.com/problems/length-of-last-word/description/
*
* algorithms
* Easy (35.14%)
* Likes: 343
* Dislikes: 0
* Total Accepted: 211.4K
* Total Submissions: 601.6K
* Testcase Example: '"Hello World"'
*P
* 给你一个字符串 s,由若干单词组成,单词前后用一些空格字符隔开。返回字符串中最后一个单词的长度。
*
* 单词 是指仅由字母组成、不包含任何空格字符的最大子字符串。
*
*
*
* 示例 1:
*
*
* 输入:s = "Hello World"
* 输出:5
*
*
* 示例 2:
*
*
* 输入:s = " fly me to the moon "
* 输出:4
*
*
* 示例 3:
*
*
* 输入:s = "luffy is still joyboy"
* 输出:6
*
*
*
*
* 提示:
*
*
* 1 <= s.length <= 10^4
* s 仅有英文字母和空格 ' ' 组成
* s 中至少存在一个单词
*
*
*/
// @lc code=start
/**
* @param {string} s
* @return {number}
*/
var lengthOfLastWord = function(s) {
let end = s.length - 1;//尾部指针
while(end >= 0 && s[end] == ' ') end--;//忽略尾部空格
if(end < 0) return 0;
let start = end;//头部指针出发
while(start >= 0 && s[start] != ' ') start--;
return end - start;
};
// @lc code=end
var lengthOfLastWord = function(s) {
let count=0;
for(let i=s.length-1;i>-1;i--){
if(s[i]===' '){
if(count==0)continue;//count为零时便一直跳过末尾的空字符
break//count非零之后,第二次遇到空字符就结束
}
count++
}
return count;
};
var lengthOfLastWord = function(s) {
//分割后空数组全部筛去
let words = s.split(' ').filter((item)=>item != '')
//注意如果原数组全部为空格,筛选后words为空数组
return words.length != 0?words[words.length-1].length:0
};
//这样反转数组还是比较耗时耗空间的
var lengthOfLastWord = function(s) {
return s.trim().split(' ').reverse()[0].length
//trim 去除首尾空格;split 按空格分割,reverse 反转数组。
};
//果然开启API之后,运行速度会降很多,但我认为这是我目前想到的最简单的写法
var lengthOfLastWord = function(s) {
return s.trim().split(" ").pop().length;
//trim 去除首尾空格;split 按空格分割,pop弹出尾部单词
};