笔者近来开始在LeetCode上学习常用的算法设计,大家也都知道LeetCode追求的是高性能,而不是说只要能解决问题就可了。因此,我有个想法:这次要把自己设计算法时的所思所想记录下来,和大家分享。也更为了抛砖引玉,和大家交流,希望有更好改进设计的能够和我分享。而自己在这个系列学习中主要采用C++语言,当然之后会跟进Python版的。下面,不在啰嗦,开始本文的正题。
题目原文要求(摘抄自LeetCode):
Given an input string, reverse the string word by word.
For example,
Given s = "the sky is blue
",
return "blue is sky the
".
- What constitutes a word?
A sequence of non-space characters constitutes a word. - Could the input string contain leading or trailing spaces?
Yes. However, your reversed string should not contain leading or trailing spaces. - How about multiple spaces between two words?
Reduce them to a single space in the reversed string.
从题目中,我们可以看到该题要求按单词反置字符串,而且在详细说明中,解释了:由空格分割的一系列非空字符就是一个单词;还要求你的算法要能处理包含前置/后置空格的情况,而且反置后的字符串不能包含前置/后置空格;还有就是要能够处理两个词之间包含多个空格的情况,将反置后的字符串,单词之间的空格全部变为一个空格。
我的解题思路:
一看到题目,我是这样想的,我可以按如下步骤处理:
1. 可以借鉴C#、JavaScript等语言中的字符函数trim(),写一个自己的trim()函数,在算法处理之前首先调用该函数,处理掉首尾的空格;
2. 从尾部开始遍历该字符串,设置两个标记变量,记录下空格和非空格字符的数量,设置一个临时变量用来存储反置后的字符串,每遇到一个单词就存储下来,遇到空格就压缩为一个空格,直到遍历到头部为止。
按照这种思路,我写出了自己的解决方案,如下所示:
class Solution {
public:
void trim(string &s)
{
int a = s.find_first_not_of(" ");
if (a == -1)
{
s = "";
return;
}
else if (a != 0)
{
s = s.substr(a, s.size() - a);
}
a = s.find_last_not_of(" ");
if (a != s.size() - 1)
{
s = s.substr(0, a + 1);
return;
}
}
void reverseWords(string &s) {
trim(s);
if (s == "")
{
return;
}
string temp = "";
int i = s.size() - 1;
int count = 0;
int sCount = 0;
while ( i >= 0)
{
if (s[i] != ' ')
{
count++;
i--;
sCount = 0;
}
else
{
sCount++;
if (sCount == 1)
{
temp += s.substr(i, count + 1);
}
i--;
count = 0;
}
}
temp += " " + s.substr(0, count);
s = temp;
trim(s);
}
};
难点分析(几个临界点需要特别注意):
1. 一定要处理字符串全空的特殊情况;
2. 当遇到第一个空格的时候来截取刚刚遍历到的单词,而且注意两个单词之间只能出现一个空格,一次要添加if (sCount==1)的判断,否则你处理后的字符串,每个单词之间就会出现多个空格,出现如下的错误:
3. 要处理第一个单词的临界情况,注意在后面添加一个空格,否则反置后最后两个单词就会连在一起,如下所示(第一行为输入,第二行是输出):
4. 要将处理完后的字符串再次调用一次trim()函数,否则就会出现下面的情况:
结果:
经过上面的分析,最终笔者的算法在线测试也通过了,最后的结果如下:
其他实现途径:
其实,还有很多解题思路,我在这里指简要的说一下我同学的做法吧。他首先,将字符串整个反置,然后再将每个单词反置,同时处理首尾字符和单词之间的多余字符,这里代码就不在给出了,有兴趣的可以自己实现一下啊。