- 作者简介:阿里非典型程序员一枚 ,记录在大厂的打怪升级之路。 一起学习Java、大数据、数据结构算法(公众号同名)
- ❤️觉得文章还不错的话欢迎大家点赞👍➕收藏⭐️➕评论,💬支持博主,记得点个大大的
关注
,持续更新🤞
————————————————-
题目描述
给定一个字符串 s
,找到 s
中最后一个单词的长度。单词以空格 ' '
分隔。
原题:LeetCode 58
思路及实现
方式一:从后向前遍历
思路
直接从字符串的末尾开始向前遍历,跳过空格,直到遇到第一个非空格字符,然后计数直到再次遇到空格或到达字符串的开头。
代码实现
Java版本
public class Solution { public int lengthOfLastWord(String s) { int length = 0; int i = s.length() - 1; // 跳过末尾的空格 while (i >= 0 && s.charAt(i) == ' ') { i--; } // 计数最后一个单词的长度 while (i >= 0 && s.charAt(i) != ' ') { length++; i--; } return length; } }
说明:Java代码通过两个循环,第一个循环跳过末尾的空格,第二个循环从最后一个非空格字符开始向前计数直到遇到空格或字符串的开头。
C语言版本
#include <string.h> int lengthOfLastWord(char *s) { int length = 0; int i = strlen(s) - 1; // 跳过末尾的空格 while (i >= 0 && s[i] == ' ') { i--; } // 计数最后一个单词的长度 while (i >= 0 && s[i] != ' ') { length++; i--; } return length; }
说明:C语言版本的代码和Java版本逻辑相同,只是语言语法上有所区别。
Python3版本
def lengthOfLastWord(s: str) -> int: # 去除字符串末尾的空格 s = s.rstrip() # 以空格分割字符串,并取最后一个单词 last_word = s.split()[-1] # 返回最后一个单词的长度 return len(last_word)
说明:Python版本利用字符串的
rstrip
方法去除末尾的空格,然后使用split
方法按空格分割字符串,并取最后一个单词返回其长度。
Golang版本
package main import ( "strings" ) func lengthOfLastWord(s string) int { // 去除字符串末尾的空格 s = strings.TrimRight(s, " ") // 以空格分割字符串,并取最后一个单词 words := strings.Split(s, " ") lastWord := words[len(words)-1] // 返回最后一个单词的长度 return len(lastWord) } func main() { // 测试代码 s := "Hello World" length := lengthOfLastWord(s) println(length) // 输出: 5 }
说明:Golang版本使用
strings
包中的TrimRight
函数去除末尾的空格,然后使用Split
函数按空格分割字符串,并取最后一个单词返回其长度。
复杂度分析
- 时间复杂度:O(n),其中n是字符串的长度。因为我们需要遍历整个字符串来找到最后一个单词的长度。
- 空间复杂度:
- Java, C, Golang版本:O(1),因为我们只使用了常量级的额外空间。
- Python版本:O(k),其中k是最后一个单词的长度,因为
split
函数会创建一个包含所有单词的列表。
方式二:正则表达式
思路
使用正则表达式来匹配并获取最后一个单词,然后返回其长度。
代码实现
Java版本
import java.util.regex.Matcher; import java.util.regex.Pattern; public class Solution { public int lengthOfLastWord(String s) { // 正则表达式匹配单词,\b表示单词边界,\w+匹配一个或多个字母、数字或下划线 Pattern pattern = Pattern.compile("\\b\\w+\\b"); Matcher matcher = pattern.matcher(s); int length = 0; // 查找所有匹配项 while (matcher.find()) { // 保留最后一个匹配项的长度 length = matcher.group().length(); } return length; } }
说明:Java版本使用
Pattern
和Matcher
类来编译和匹配正则表达式。\\b\\w+\\b
正则表达式匹配单词边界内的单词。在循环中,我们不断查找匹配项,并保留最后一个匹配项的长度。
C语言版本
C语言标准库并不直接支持正则表达式,因此通常需要使用第三方库如POSIX正则表达式库(regex.h)或PCRE库。这里以POSIX正则表达式库为例进行演示。
首先,确保你的系统支持POSIX正则表达式库,并且你的编译器链接了该库。
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <regex.h> int lengthOfLastWord(char *s) { regex_t regex; regmatch_t match; int ret; char errbuf[100]; // 编译正则表达式,匹配单词边界内的单词 ret = regcomp(®ex, "\\b\\w+\\b", REG_EXTENDED); if (ret) { regerror(ret, ®ex, errbuf, sizeof(errbuf)); fprintf(stderr, "Regex compilation failed: %s\n", errbuf); return 0; } int length = 0; char *ptr = s; // 查找所有匹配项 while ((ret = regexec(®ex, ptr, 1, &match, 0)) == 0) { // 如果找到匹配项,更新长度为当前匹配项的长度 length = match.rm_eo - match.rm_so; // 移动指针到下一个可能的位置 ptr += match.rm_eo; } // 释放正则表达式对象 regfree(®ex); // 如果正则表达式执行失败且不是因为没有更多匹配项,打印错误信息 if (ret != REG_NOMATCH) { regerror(ret, ®ex, errbuf, sizeof(errbuf)); fprintf(stderr, "Regex match failed: %s\n", errbuf); } return length; } int main() { char s[] = "Hello World"; int length = lengthOfLastWord(s); printf("Length of last word: %d\n", length); // 输出: 5 return 0; }
说明:C语言版本使用POSIX的
regex.h
库来编译和匹配正则表达式。注意,编译时需要链接正则表达式库(通常是使用-lregex
选项)。正则表达式的使用和Java版本类似,但在C语言中需要手动管理字符串指针来迭代查找匹配项。
Python3版本
import re def lengthOfLastWord(s: str) -> int: # 使用正则表达式匹配最后一个单词 last_word = re.search(r'\b\w+\b$', s) # 如果找到最后一个单词,返回其长度,否则返回0 return len(last_word.group()) if last_word else 0
Golang版本
Golang的正则表达式库功能强大且易于使用。
package main import ( "fmt" "regexp" ) func lengthOfLastWord(s string) int { // 编译正则表达式,匹配单词边界内的单词 re := regexp.MustCompile(`\b\w+\b`) // 查找所有匹配项 matches := re.FindAllString(s, -1) // 如果找到匹配项,返回最后一个匹配项的长度 if len(matches) > 0 { return len(matches[len(matches)-1]) } // 如果没有找到匹配项,返回0 return 0 } func main() { s := "Hello World" length := lengthOfLastWord(s) fmt.Println(length) // 输出: 5 }
复杂度分析:
- 时间复杂度:O(n),其中n是字符串s的长度。Golang的正则表达式引擎同样会遍历整个字符串来查找匹配项。
- 空间复杂度:O(k),其中k是匹配到的单词数量。和Java和C语言版本类似,理论空间复杂度与匹配到的单词数量成正比。但实际上,由于我们只关心最后一个单词的长度,因此空间复杂度可以视为O(1)。
总结
方式 | 优点 | 缺点 | 时间复杂度 | 空间复杂度 |
方式一(字符串分割) | 1. 不依赖正则表达式库,实现相对独立。 | 1. 代码量较大,实现逻辑较复杂。 | O(n) | O(n) |
方式二(正则表达式) | 1. 代码简洁,易于理解。 | 1. 依赖正则表达式库,可能不是性能最优解。 | O(n) | O(1) |
相似题目
相似题目 | 难度 | 链接 |
LeetCode 58 - 最后一个单词的长度 | 简单 | LeetCode 58 |
LeetCode 151 - 翻转字符串里的单词 | 中等 | LeetCode 151 |
LeetCode 434 - 字符串中的单词数 | 简单 | LeetCode 434 |
LeetCode 14 - 最长公共前缀 | 简单 | LeetCode 14 |
LeetCode 647 - 回文子串 | 中等 | LeetCode 647 |
LeetCode 459 - 重复的子字符串 | 困难 | LeetCode 459 |
LeetCode 5 - 最长回文子串 | 中等 | LeetCode 5 |
这些题目涵盖了字符串处理的不同方面,从简单的字符串操作到复杂的回文串检测,通过解决这些题目,可以加深对字符串处理的理解和提高相关技能。
欢迎一键三连(关注+点赞+收藏),技术的路上一起加油!!!代码改变世界
- 关于我:阿里非典型程序员一枚 ,记录在大厂的打怪升级之路。 一起学习Java、大数据、数据结构算法(公众号同名),回复暗号,更能获取学习秘籍和书籍等