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

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

问题描述

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

约束条件:

  • 每个单词非空
  • 总字符长度不超过 103103
  • 单词间使用单个空格分隔

示例:

1

2

3

4

输入:HelloNowcoder

输出:13

输入:A B C D

输出:1

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

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

#include <iostream>

#include <string>

usingnamespacestd;

intmain() {

string str;

getline(cin, str);

intlen = 0;

inti = str.size() - 1;

// 跳过末尾可能的空格(虽然题目说没有,但增加鲁棒性)

while(i >= 0 && str[i] ==' ') i--;

// 计算最后一个单词的长度

while(i >= 0 && str[i] !=' ') {

len++;

i--;

}

cout << len << endl;

return0;

}

算法分析

时间复杂度:O(n)

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

空间复杂度:O(1)

只使用了常数个额外变量

优点:

  1. 高效:只需要一次遍历
  2. 节省空间:不需要额外存储
  3. 鲁棒性好:能处理末尾有空格的情况

解法二:使用rfind方法

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

#include <iostream>

#include <string>

usingnamespacestd;

intmain() {

string str;

getline(cin, str);

// 从后向前查找最后一个空格的位置

size_tpos = str.rfind(' ');

if(pos == string::npos) {

// 没有空格,整个字符串就是一个单词

cout << str.size() << endl;

}else{

// 计算最后一个单词的长度

cout << str.size() - pos - 1 << endl;

}

return0;

}

关键点说明

  • rfind(' '): 从字符串末尾开始查找空格
  • string::npos: 表示未找到,值为-1(但类型为size_t,所以是最大无符号数)
  • 注意处理只有一个单词的情况

解法三:使用stringstream分割

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

#include <iostream>

#include <string>

#include <sstream>

usingnamespacestd;

intmain() {

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;

return0;

}

算法特点

优点:

  1. 代码简洁易读
  2. 自动处理多余空格
  3. 容易扩展(如需要处理所有单词)

缺点:

  1. 需要额外的字符串拷贝
  2. 使用stringstream有额外开销
  3. 需要存储最后一个单词的完整副本

解法四:双指针法

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

#include <iostream>

#include <string>

usingnamespacestd;

intmain() {

string str;

getline(cin, str);

intright = str.size() - 1;

// 右指针:跳过末尾空格

while(right >= 0 && str[right] ==' ') right--;

intleft = right;

// 左指针:找到单词开头

while(left >= 0 && str[left] !=' ') left--;

// 计算长度

cout << right - left << endl;

return0;

}

算法性能对比

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

边界条件处理

1. 空字符串

1

2

3

4

5

// 在从后向前遍历法中

if(str.empty()) {

cout << 0 << endl;

return0;

}

2. 全是空格

1

2

3

4

5

// 在从后向前遍历法中,第一个while循环后i可能为-1

if(i < 0) {

cout << 0 << endl;

return0;

}

3. 末尾有多个空格

1

2

// 所有方法都应该处理这种情况

// 解法一和四已经通过while循环处理

扩展问题

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

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

#include <iostream>

#include <string>

usingnamespacestd;

intmain() {

string str;

getline(cin, str);

intcount = 0;

inti = str.size() - 1;

// 跳过末尾空格

while(i >= 0 && str[i] ==' ') i--;

// 找倒数第一个单词

while(i >= 0 && str[i] !=' ') i--;

// 跳过单词间的空格

while(i >= 0 && str[i] ==' ') i--;

// 找倒数第二个单词的末尾

intend = i;

while(i >= 0 && str[i] !=' ') i--;

cout << end - i << endl;

return0;

}

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

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

#include <iostream>

#include <string>

#include <sstream>

usingnamespacestd;

intmain() {

string str;

getline(cin, str);

stringstream ss(str);

string word;

intcount = 0;

while(ss >> word) {

count++;

}

cout << count << endl;

return0;

}

3. 获取最长的单词

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

#include <iostream>

#include <string>

#include <sstream>

usingnamespacestd;

intmain() {

string str;

getline(cin, str);

stringstream ss(str);

string word, longest_word;

intmax_len = 0;

while(ss >> word) {

if(word.size() > max_len) {

max_len = word.size();

longest_word = word;

}

}

cout <<"最长单词: "<< longest_word <<", 长度: "<< max_len << endl;

return0;

}

实际应用场景

1. 命令行工具

1

2

// 实现类似Linux的wc命令,统计单词数

// 可以扩展为获取最后一行或最后一个单词

2. 文本编辑器

1

2

// 在代码编辑器中,获取光标所在单词的长度

// 用于自动补全或语法高亮

3. 日志分析

1

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

4. 自然语言处理

1

2

// 在NLP预处理中,获取句子的最后一个词

// 用于语言模型训练或情感分析

测试用例

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

voidtest() {

// 测试用例集合

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. 使用引用避免拷贝

1

2

3

4

// 在处理大字符串时,使用const引用

voidprocessString(conststring& str) {

// 处理逻辑

}

2. 预分配内存

1

2

// 如果知道最大长度,可以预分配

str.reserve(1000);// 根据题目约束

3. 使用C风格字符串

1

2

3

4

5

6

7

8

9

10

11

// 在性能关键场景,可以使用C风格字符串

intgetLastWordLength(constchar* str) {

intlen = 0;

inti =strlen(str) - 1;

while(i >= 0 && str[i] ==' ') i--;

while(i >= 0 && str[i] !=' ') {

len++;

i--;

}

returnlen;

}

常见错误

1. 忘记处理npos

1

2

3

// 错误示例

size_tpos = str.rfind(' ');

intlength = str.size() - pos - 1;// 当pos为npos时,计算错误

2. 未考虑末尾空格

1

2

3

4

5

// 错误示例

intpos = str.rfind(' ');

if(pos != -1) {

cout << str.size() - pos - 1 << endl;// 如果末尾有空格,结果错误

}

3. 越界访问

1

2

3

// 错误示例

inti = str.size() - 1;

while(str[i] ==' ') i--;// 如果字符串为空,i为-1,访问越界

总结

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

  1. 字符串遍历技巧:从后向前遍历是解决此类问题的关键
  2. 边界条件处理:空字符串、空格、单个单词等情况都需要考虑
  3. 算法选择:根据具体需求选择最合适的算法
  4. 代码鲁棒性:处理各种异常输入情况

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

  • 效率高,空间复杂度低
  • 代码清晰,易于理解
  • 鲁棒性好,能处理各种边界情况

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