【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. 代码鲁棒性:处理各种异常输入情况

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

  • 效率高,空间复杂度低

  • 代码清晰,易于理解

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

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

相关推荐
myloveasuka2 小时前
时间相关类
java·开发语言
zyb11475824332 小时前
集合的学习
开发语言·python·学习
程序员柒叔2 小时前
Dify 版本追踪 - 2026-W12
人工智能·github·工作流·dify
6+h2 小时前
【java IO】转换流 + 对象流 + 序列化详解
java·开发语言
荣光波比2 小时前
OpenClaw Windows 10 WSL2 安装与配置指南+飞书接入(使用腾讯云Coding Plan)
windows·飞书·腾讯云
沈阳信息学奥赛培训2 小时前
#define 和 typedef 的区别
开发语言·c++
Laurence2 小时前
CMake 查找、打印 Qt 所有 Components / 模块列表
开发语言·qt·cmake·打印·查找·所有组件·所有模块
秋知叶i2 小时前
【git命令】Git 删除远程分支保姆级教程(含缓存清理 + 本地残留绝杀)
git·elasticsearch·缓存
程序猿编码2 小时前
轻量又灵活:一款伪造TCP数据包的iptables扩展实现解析(C/C++代码实现)
linux·c语言·网络·c++·tcp/ip·内核·内核模块