【C++】获取字符串最后一个单词长度的多种解法

引言

在字符串处理中,获取最后一个单词的长度是一个常见问题。这个问题在文本处理、编译原理、自然语言处理等领域都有广泛应用。本文将详细介绍多种解决该问题的方法,并分析各自的优缺点。

目录

引言

问题描述

解法一:从后向前遍历法(推荐)

算法分析

解法二:使用rfind方法

关键点说明

解法三:使用stringstream分割

算法特点

解法四:双指针法

算法性能对比

边界条件处理

[1. 空字符串](#1. 空字符串)

[2. 全是空格](#2. 全是空格)

[3. 末尾有多个空格](#3. 末尾有多个空格)

扩展问题

[1. 获取倒数第二个单词的长度](#1. 获取倒数第二个单词的长度)

[2. 统计句子中单词的数量](#2. 统计句子中单词的数量)

[3. 获取最长的单词](#3. 获取最长的单词)

实际应用场景

[1. 命令行工具](#1. 命令行工具)

[2. 文本编辑器](#2. 文本编辑器)

[3. 日志分析](#3. 日志分析)

[4. 自然语言处理](#4. 自然语言处理)

测试用例

优化技巧

[1. 使用引用避免拷贝](#1. 使用引用避免拷贝)

[2. 预分配内存](#2. 预分配内存)

[3. 使用C风格字符串](#3. 使用C风格字符串)

常见错误

[1. 忘记处理npos](#1. 忘记处理npos)

[2. 未考虑末尾空格](#2. 未考虑末尾空格)

[3. 越界访问](#3. 越界访问)

总结


问题描述

给定一个由多个单词组成的句子,每个单词由大小写字母混合构成,单词间使用单个空格分隔。要求输出最后一个单词的长度。

约束条件:

  • 每个单词非空

  • 总字符长度不超过 103103

  • 单词间使用单个空格分隔

示例:

text

复制代码
输入:HelloNowcoder
输出:13

输入:A B C D
输出:1

解法一:从后向前遍历法(推荐)

cpp

复制代码
#include <iostream>
#include <string>
using namespace std;

int main() {
    string str;
    getline(cin, str);
    
    int len = 0;
    int i = str.size() - 1;
    
    // 跳过末尾可能的空格(虽然题目说没有,但增加鲁棒性)
    while (i >= 0 && str[i] == ' ') i--;
    
    // 计算最后一个单词的长度
    while (i >= 0 && str[i] != ' ') {
        len++;
        i--;
    }
    
    cout << len << endl;
    return 0;
}

算法分析

时间复杂度: O(n)

  • 最坏情况下需要遍历整个字符串

空间复杂度: O(1)

  • 只使用了常数个额外变量

优点:

  1. 高效:只需要一次遍历

  2. 节省空间:不需要额外存储

  3. 鲁棒性好:能处理末尾有空格的情况

解法二:使用rfind方法

cpp

复制代码
#include <iostream>
#include <string>
using namespace std;

int main() {
    string str;
    getline(cin, str);
    
    // 从后向前查找最后一个空格的位置
    size_t pos = str.rfind(' ');
    
    if (pos == string::npos) {
        // 没有空格,整个字符串就是一个单词
        cout << str.size() << endl;
    } else {
        // 计算最后一个单词的长度
        cout << str.size() - pos - 1 << endl;
    }
    
    return 0;
}

关键点说明

  • rfind(' '): 从字符串末尾开始查找空格

  • string::npos: 表示未找到,值为-1(但类型为size_t,所以是最大无符号数)

  • 注意处理只有一个单词的情况

解法三:使用stringstream分割

cpp

复制代码
#include <iostream>
#include <string>
#include <sstream>
using namespace std;

int main() {
    string str;
    getline(cin, str);
    
    stringstream ss(str);
    string word, last_word;
    
    // 读取所有单词,最后一个存储在last_word中
    while (ss >> word) {
        last_word = word;
    }
    
    cout << last_word.size() << endl;
    return 0;
}

算法特点

优点:

  1. 代码简洁易读

  2. 自动处理多余空格

  3. 容易扩展(如需要处理所有单词)

缺点:

  1. 需要额外的字符串拷贝

  2. 使用stringstream有额外开销

  3. 需要存储最后一个单词的完整副本

解法四:双指针法

cpp

复制代码
#include <iostream>
#include <string>
using namespace std;

int main() {
    string str;
    getline(cin, str);
    
    int right = str.size() - 1;
    
    // 右指针:跳过末尾空格
    while (right >= 0 && str[right] == ' ') right--;
    
    int left = right;
    // 左指针:找到单词开头
    while (left >= 0 && str[left] != ' ') left--;
    
    // 计算长度
    cout << right - left << endl;
    
    return 0;
}

算法性能对比

方法 时间复杂度 空间复杂度 优点 缺点
从后向前遍历 O(n) O(1) 效率高,内存少 需要手动处理边界
rfind方法 O(n) O(1) 代码简洁 需要处理npos
stringstream O(n) O(n) 自动处理空格 额外开销大
双指针法 O(n) O(1) 思路清晰 需要两个指针

边界条件处理

1. 空字符串

cpp

复制代码
// 在从后向前遍历法中
if (str.empty()) {
    cout << 0 << endl;
    return 0;
}

2. 全是空格

cpp

复制代码
// 在从后向前遍历法中,第一个while循环后i可能为-1
if (i < 0) {
    cout << 0 << endl;
    return 0;
}

3. 末尾有多个空格

cpp

复制代码
// 所有方法都应该处理这种情况
// 解法一和四已经通过while循环处理

扩展问题

1. 获取倒数第二个单词的长度

cpp

复制代码
#include <iostream>
#include <string>
using namespace std;

int main() {
    string str;
    getline(cin, str);
    
    int count = 0;
    int i = str.size() - 1;
    
    // 跳过末尾空格
    while (i >= 0 && str[i] == ' ') i--;
    
    // 找倒数第一个单词
    while (i >= 0 && str[i] != ' ') i--;
    
    // 跳过单词间的空格
    while (i >= 0 && str[i] == ' ') i--;
    
    // 找倒数第二个单词的末尾
    int end = i;
    while (i >= 0 && str[i] != ' ') i--;
    
    cout << end - i << endl;
    return 0;
}

2. 统计句子中单词的数量

cpp

复制代码
#include <iostream>
#include <string>
#include <sstream>
using namespace std;

int main() {
    string str;
    getline(cin, str);
    
    stringstream ss(str);
    string word;
    int count = 0;
    
    while (ss >> word) {
        count++;
    }
    
    cout << count << endl;
    return 0;
}

3. 获取最长的单词

cpp

复制代码
#include <iostream>
#include <string>
#include <sstream>
using namespace std;

int main() {
    string str;
    getline(cin, str);
    
    stringstream ss(str);
    string word, longest_word;
    int max_len = 0;
    
    while (ss >> word) {
        if (word.size() > max_len) {
            max_len = word.size();
            longest_word = word;
        }
    }
    
    cout << "最长单词: " << longest_word << ", 长度: " << max_len << endl;
    return 0;
}

实际应用场景

1. 命令行工具

cpp

复制代码
// 实现类似Linux的wc命令,统计单词数
// 可以扩展为获取最后一行或最后一个单词

2. 文本编辑器

cpp

复制代码
// 在代码编辑器中,获取光标所在单词的长度
// 用于自动补全或语法高亮

3. 日志分析

cpp

复制代码
// 分析日志文件的最后一个状态码或错误信息

4. 自然语言处理

cpp

复制代码
// 在NLP预处理中,获取句子的最后一个词
// 用于语言模型训练或情感分析

测试用例

cpp

复制代码
void test() {
    // 测试用例集合
    vector<pair<string, int>> test_cases = {
        {"HelloNowcoder", 13},
        {"A B C D", 1},
        {"Hello World", 5},
        {"a", 1},
        {"   ", 0},  // 全是空格
        {"hello   ", 5},  // 末尾有空格
        {"  hello", 5},  // 开头有空格
        {"multiple   spaces   between", 7},  // 多个空格
        {"", 0},  // 空字符串
        {"12345 67890", 5},
        {"The quick brown fox jumps over the lazy dog", 3}
    };
    
    for (auto& test_case : test_cases) {
        // 测试各个算法
        cout << "输入: \"" << test_case.first << "\", 期望: " << test_case.second << endl;
    }
}

优化技巧

1. 使用引用避免拷贝

cpp

复制代码
// 在处理大字符串时,使用const引用
void processString(const string& str) {
    // 处理逻辑
}

2. 预分配内存

cpp

复制代码
// 如果知道最大长度,可以预分配
str.reserve(1000);  // 根据题目约束

3. 使用C风格字符串

cpp

复制代码
// 在性能关键场景,可以使用C风格字符串
int getLastWordLength(const char* str) {
    int len = 0;
    int i = strlen(str) - 1;
    
    while (i >= 0 && str[i] == ' ') i--;
    
    while (i >= 0 && str[i] != ' ') {
        len++;
        i--;
    }
    
    return len;
}

常见错误

1. 忘记处理npos

cpp

复制代码
// 错误示例
size_t pos = str.rfind(' ');
int length = str.size() - pos - 1;  // 当pos为npos时,计算错误

2. 未考虑末尾空格

cpp

复制代码
// 错误示例
int pos = str.rfind(' ');
if (pos != -1) {
    cout << str.size() - pos - 1 << endl;  // 如果末尾有空格,结果错误
}

3. 越界访问

cpp

复制代码
// 错误示例
int i = str.size() - 1;
while (str[i] == ' ') i--;  // 如果字符串为空,i为-1,访问越界

总结

获取字符串最后一个单词的长度是一个基础的字符串处理问题,但它涉及了许多重要的编程概念:

  1. 字符串遍历技巧:从后向前遍历是解决此类问题的关键

  2. 边界条件处理:空字符串、空格、单个单词等情况都需要考虑

  3. 算法选择:根据具体需求选择最合适的算法

  4. 代码鲁棒性:处理各种异常输入情况

推荐方法:从后向前遍历法

  • 效率高,空间复杂度低

  • 代码清晰,易于理解

  • 鲁棒性好,能处理各种边界情况

掌握这个问题的解法不仅能帮助解决类似问题,还能提高字符串处理的基本功。在实际开发中,根据具体场景选择最合适的方法才是最重要的。

相关推荐
JJJennie77728 分钟前
Gemini 3.7 Flash 上线,Google 想让 AI 多干活
开发语言·javascript·ecmascript
峰向AI33 分钟前
24000本书,一个项目全搞定:这个开源宝藏让我重新认识了读书
github
mCell1 小时前
GitHub Actions 玩法大赏:一台远程主机的七种活法
linux·github·agent
wuyk5551 小时前
Python 第三章:列表 List
服务器·开发语言·python
笨鸟先飞,勤能补拙1 小时前
从预测到决策:人工智能与机器学习的系统方法、工程闭环与现实边界
大数据·人工智能·windows·python·机器学习·密码学
hajimi1 小时前
Agent Skill 实战:我把大疆行业无人机上云的坑,固化成了一个技能包
github
Evand J2 小时前
【MATLAB例程,车联网7】CACC网联车辆协同控制:ACC对比、V2X时延丢包与队列稳定性,附例程下载链接
开发语言·matlab·车联网
程序员-李俞2 小时前
Mistral OCR 4真正改变的不是“识字”:文档AI正在变成Agent的数据入口
人工智能·windows·ai作画·aigc·ocr·ai编程·ai写作
要努力点2 小时前
Python入门第六课
开发语言·python
萧瑟余晖3 小时前
Java深入解析篇三十三之消息队列
java·开发语言