题目描述
在每日一练中有一道反转字符串里单词的题目,具体如下:
给定一个字符串,逐个翻转字符串中的所有单词 。单词是由非空格字符组成的字符串。至少有一个空格将字符串中的单词分隔开。
要求:
1、返回一个翻转字符串中单词顺序并用单个空格相连的字符串。
2、给定的输入字符串可以在前面、后面或者单词间包含多余的空格。
3、翻转后单词间应当仅用一个空格分隔。
4、翻转后的字符串中不应包含额外的空格。
标准答案中使用了栈来处理,我想用其他比较简单,容易理解的方式处理,同时不考虑时间复杂度。
想法思路
首先想到的是字符串翻转中使用的递归方法,但是并不容易实现。最后决定将每个单词首字母在字符数组中的下标取出,然后根据下标输出每个单词,注意单词间的空格即可。
代码编写
首先给定两个数组,一个用于存储给定字符串,一个放首字母下标:
char str[50] = " nothing is impossible ";
char index[50] = {0};
然后根据前一个字符是空格来确定首字母,并保存其下标:
while(str[i] != '\0')
{
if(i == 0 && str[i] > 0x20) j++;
else if(str[i - 1] == 0x20 && str[i] > 0x20) index[j++] = i;
i++;
}
这里加入i == 0的判断是因为1、给定字符串有可能第一个字符是空格,此时就需要else if来判断index[0]的值,若不是空格,index[0] = 0;2、else if的判断条件在i是0时不能使用。
之后反序循环index,根据下标将单词输出,注意单词之间加一个空格,完整程序如下:
#include <iostream>
using namespace std;
int main(int argc, char *argv[])
{
char str[50] = " nothing is impossible ";
char index[50] = {0};
int i,j,outIndex;
i = j = 0;
while(str[i] != '\0')
{
if(i == 0 && str[i] > 0x20) j++;
else if(str[i - 1] == 0x20 && str[i] > 0x20) index[j++] = i;
i++;
}
for(i = j - 1;i >= 0;i--)
{
outIndex = index[i];
while(str[outIndex] != '\0' && str[outIndex] > 0x20)
{
cout << str[outIndex];
outIndex++;
}
cout << " ";
}
return 0;
}
不论字符串中空格在哪里,如程序中给定的字符串中前后均有多余的空格,输出字符串中只有每个单词间一个空格:
小插曲
在程序第一次编写完成进行测试时,如果字符串开头有空格,输出就不正确,最后查出问题出在定位首字母的部分,其初始代码如下:
while(str[i++] != '\0')
{
if(i == 0 && str[i] > 0x20) j++;
else if(str[i - 1] == 0x20 && str[i] > 0x20) index[j++] = i;
}
问题就出现在while语句上,while语句是先执行str[i] != ‘\0’,然后i++,再执行循环体部分。这样就导致i第一次进入循环体就为1,if判断语句就失效了,index[0]始终等于0,所以当字符串开头有空格显示就不完整。
由此可以看出while与for在处理i++等自增自减运算上的不同,for总是在循环体之后再执行,而while则是再循环体之前,具体for的实验可以参看我之前的文章:
for循环测试题的小错误
while也可以做一些实验来验证,首先用for写出如下程序:
#include <stdio.h>
int main()
{
int i = 0;
for(;i <= 10;i++) printf("%d ",i);
return 0;
}
结果如下:
执行部分改为while:
int j = 0;
while(j++ <= 10) printf("%d ",j);
可以看出明显的不同,while判断条件中的自加运算确实在循环体之前执行。等价于:
while(j <= 10)
{
j++;
printf("%d ",j);
}
而do…while也同样适用:
do
{
printf("%d ",j);
}while(j++ <= 10);
等价于:
printf("%d ",j);
do
{
j++;
printf("%d ",j);
}while(j <= 10);
其结果均为: