从这次开始,就是真枪实弹啦,以后就是真正有些坑的算法题了哦~
这次的练习是在上次的基础之上,一个字符串逆序非常简单,但是对于一个句子来说,有多个单词,将它们每个都逆序呢?这也是面试经常考的题,来看一下~
将一个字符串里面所有的单词都逆序,但是单词顺序不变。
例如:
转换前:
This is a cat, I like it.
转换后:
sihT si a tac, I ekil ti.
#include<iostream>
#include<string>
#include<cstdlib>
using namespace std;
bool is_letter(char c)
{
return ((c >= 'A' && c <= 'Z')||(c >= 'a' && c <= 'z'));
}
void rev_str(string & str)
{
// cout << str <<endl;
int word_index = 0;
int word_size = 0;
for(int i = 0; i < str.length(); i++)
{
if((i == 0 && str[i] != ' ')||(str[i-1] == ' ' && is_letter(str[i])))
{
word_index = i;
// cout<<"word_index"<<word_index<<endl;
for(int j = i; is_letter(str[j]); j++)
{
word_size++;
}
// cout<<"word_size"<<word_size<<endl;
for(int j = word_index; j < word_index + word_size/2; j++)
{
swap(str[j], str[word_index + word_size - (j - word_index) - 1]);
}
// cout<<str<<endl;
word_size = 0;
}
}
return;
}
int main()
{
string str = "This is a cat, I like it.";
rev_str(str);
cout << str <<endl;
system("pause");
return 0;
}
这里面有两个坑,一个是空格,一个是标点。
首先,bool is_letter(char c)函数是用来判断字符 c 是否是一个字母的,如果是字母则返回true,否则返回false。
然后就是算法主体了。整体思路就是通过标记逐个判断单词的位置和长度然后对单词进行逆序操作。
比如对于This is a cat.这句话,首先定义位置标记及长度变量:
int word_index = 0;//当前单词位置
int word_size = 0;//当前单词长度
那么问题来了,如何判断遇到单词了呢?
有两种判断情况:
- 最一般的当然是句子内部的单词,如果判断出当前位置是字母,前一个位置是空格,那么这个位置自然是单词的起始坐标啦
- 还有第一个单词的情况,第一个单词需要特别判断,如果i==0,并且第0个位置是字母,那么0就是单词起始坐标啦,这是最容易被忽略的地方哦
另外,还需要判断单词在哪里结束的。
同样很简单,如果从单词起始坐标开始,判断后面的字符是不是字母,直到判断出不是字母了,就停止判断,这样单词长度也出来了。
这样,找到了单词位置和单词长度,就要对单词动刀了。
当然方法也类似疯狼算法日记0001-字符串逆序中所说的,比如This这个单词,首先变成shiT,然后变成sihT,即单词首尾互换,然后逐渐向中间推进:
for(int j = word_index; j < word_index + word_size/2; j++)
{
swap(str[j], str[word_index + word_size - (j - word_index) - 1]);
}
当然, 坐标的计算比较麻烦这个只能大家自己在纸上演算一遍啦~
每个单词都这样处理,知道整个句子被处理完,任务就完成啦~