1. 题目
题目描述.
给你一个字符串 s,由若干单词组成,单词前后用一些空格字符隔开。返回字符串中 最后一个 单词的长度。
单词 是指仅由字母组成、不包含任何空格字符的最大子字符串。
示例
输入:s = "Hello World"
输出:5
输入:s = " fly me to the moon "
输出:4
输入:s = "luffy"
输出:5
约束
-
(1 <= s.length <= 10^4)
-
s仅有英文字母和空格' '组成 -
s中至少存在一个单词
2. 最佳解题思路描述(从后往前遍历,最优)
-
从字符串末尾向前扫描:
-
先跳过末尾所有连续空格;
-
再持续计数直到遇到空格或到达字符串开头,计数即为最后单词长度;
-
-
优势:无需完整遍历整个字符串,遇到目标即可停止;
-
时间 (O(n)) 最坏,实际常数更小;空间 (O(1))。
3. 我的可优化代码(逻辑正确可 AC,但思路繁琐,变量冗余)
class Solution {
public:
int lengthOfLastWord(string s) {
int last=0,cur=0;
int flag = 0;
for(int i = 0;i<s.length();i++){
if(s[i]!=' '){
cur++;
flag = 0;
}
else if(s[i] == ' '&& flag != 1){
last = cur;
cur = 0;
flag = 1;
}
}
if(0 == cur){
return last;
}
else{
return cur;
}
}
};
代码说明
-
正确性:逻辑无 bug,可以通过全部测试用例;
-
cur:当前连续单词长度; -
last:上一段完整单词长度; -
flag:标记是否刚进入空格段,避免多个连续空格重复覆盖 last; -
循环结束后如果末尾不是空格,直接返回 cur,否则返回 last。
-
-
缺陷与可优化点:
-
正向完整遍历,必须走完整个字符串,末尾大量空格时做无用遍历;
-
变量过多:
last、cur、flag三个变量维护状态,逻辑绕,可读性差; -
多层 if 分支,判断条件复杂,容易写错标记逻辑。
-
4. 最优标准代码(逆序遍历,极简)
class Solution {
public:
int lengthOfLastWord(string s) {
int len = 0;
int i = s.size() - 1;
// 跳过尾部空格
while (i >= 0 && s[i] == ' ') {
i--;
}
// 统计最后单词长度
while (i >= 0 && s[i] != ' ') {
len++;
i--;
}
return len;
}
};
5. 总结
-
你的正向遍历写法可以通过,但变量多、逻辑复杂,不是最优;
-
本题最优策略:逆序扫描,先去尾空格,再统计单词;
-
核心边界:字符串尾部带连续空格、仅单个单词、单词间多空格,逆序天然兼容;
-
不需要保存上一个单词长度,只需要一次计数。
6. 相关知识拓展
拓展 1:stringstream 分割单词(偷懒写法,面试不推荐)
#include <sstream>
int lengthOfLastWord(string s) {
string word;
stringstream ss(s);
while (ss >> word);
return word.size();
}
利用流自动忽略空格,循环读完最后一个单词;但创建流对象有额外开销。
拓展 2:正向简洁优化版(去掉 flag)
不使用 flag,遇到空格直接重置 cur,每次非空格持续更新 last:
int lengthOfLastWord(string s) {
int len = 0;
int last = 0;
for (char c : s) {
if (c != ' ') {
len++;
last = len;
} else {
len = 0;
}
}
return last;
}
拓展 3:复杂度对比
-
正向遍历(你的代码):(O(n)),(O(1)),全程遍历;
-
逆序最优遍历:(O(n)),(O(1)),提前终止;
-
stringstream 分割:(O(n)),额外容器空间。