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

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

  • 效率高,空间复杂度低

  • 代码清晰,易于理解

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

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

相关推荐
I Promise342 分钟前
C++ 基础数据结构与 STL 容器详解
开发语言·数据结构·c++
morrisonwu5 分钟前
kafka4.2对应php rdkafka扩展安装以及php的producer和consumer写法及避坑
开发语言·php
Lyyaoo.8 分钟前
【JAVA基础面经】== 和 equals() 的区别
java·开发语言·jvm
魔都吴所谓12 分钟前
【Ubuntu】离线环境下Git LFS(deb包)安装与验证完整教程
linux·git·ubuntu
报错小能手13 分钟前
ios开发方向——swift并发进阶核心 async/await 详解
开发语言·ios·swift
青花瓷18 分钟前
采用QT下MingW编译opencv4.8.1
开发语言·qt
旖-旎28 分钟前
链表(两两交换链表中的节点)(2)
数据结构·c++·学习·算法·链表·力控
赫瑞28 分钟前
Java中的日期类
java·开发语言
吕司30 分钟前
Linux线程同步
linux·服务器·开发语言
dyj09534 分钟前
OpenClaw小龙虾本地部署【Windows系统 + 接入飞书】
windows·飞书