今天开始在https://oj.leetcode.com点击打开链接上刷题,好囧啊~但是还是决定开始记录刷题吧。也是大学里没做的,现在慢慢做!加油!!
题目:
Given an input string, reverse the string word by word.
For example, Given s = "the sky is blue
", return "blue is sky the
".
解题思路:
方案1.切分字符串获得每个词,不断将字符串逆序拼接
void reverseWords(string &str) {
const char * str_char = str.c_str();
int len = str.length();
string result = "";
for(int i = 0; i < len; )
{
while(i < len && str_char[i] == ' ') i++;
if(i == len) break;
int start = i;
while(i < len && str_char[i] != ' ') i++;;
string temp = str.substr(start,i-start) +" "+ result;
result = temp;
}
string ss(result.substr(0,result.length()-1));
str = ss;
}
解析:这个方案中使用了C++的substr函数,赋值指定位置和长度的字符串,核心思想为string temp = str.substr(start,i-start) +" "+ result; result = temp;两行代码将word顺序不断逆序拼接。这种代码结构简洁,思路清晰,但是由于字符串拼接本身和substr函数本身很耗时的缘故,该方法看起来时间复杂度为O(n),实际上耗时超过该值. Run time 44 ms.
方案2 将字符串整个逆转过来,遇到空格作为一个词再次求逆
void reverseWords(string &str) {
int len = str.length();
char *revers_str = new char[len+1]; //字符串逆序列
const char* temparray = str.c_str();
for(int i = 0 ; i < len; ++i)
{
revers_str[i] = temparray[ len - i -1];
}
revers_str[str.length()]='\0';
int start = 0,index = 0;
char *result = new char[len+1];
while(start < len && revers_str[start] == ' ') start++;//去除起始的空格
for(int i = start; i < len;)
{
int startindex = i; // 词的起始位置
while(i < len && revers_str[i] != ' ') i++;
int endindex = i -1;//词的终止位置
for( int j = endindex; j >= startindex; j--)
result[index++] = revers_str[j];
while(i < len && revers_str[i] == ' ' ) i++;//去除空格
if( i < len ) result[index++]=' '; //word space
}
result[index]='\0';
string ss(result);
str = ss;
delete revers_str, result;
}
解析:这个方案中使用了C的c_str函数,获取字符串的字符数组,用一个循环获得逆序,之后顺序读取字符判断,获得每个词的起始终止位置,再次逆序使得词正确。这个方案虽然没有字符串拼接,但是两遍循环和字符逆序,相当于每次都要至少遍历3次字符串,耗时也很长 Run time 40ms.
方案3 改进的逆序法,使用在逆序时就记录词的位置,可以在第二次扫描时直接加入空格成为答案。
void reverseWords(string &str) {
int len = str.length();
char *revers_str = new char[len+1];
int* space_indexs = new int[len+1];
space_indexs[0] = 0;
int word_num = 0, revers_len = 0;
const char* temparray = str.c_str();
for(int i = 0 ; i < len;) //字符串求逆 并记录space位置
{
while(i < len && temparray[ len - i -1] == ' ') i++;
if(i == len) break;
while(i < len && temparray[ len - i -1] != ' ')
{
revers_str[revers_len++] = temparray[ len - i -1];
i++;
}
space_indexs[word_num++] = revers_len -1;
}
revers_str[revers_len]='\0';
int result_len = 0;
char *result = new char[len+1];
for(int j =space_indexs[0]; j >=0 ; j--) //记录第一个词
result[result_len++] = revers_str[j];
for(int i = 1; i < word_num; i++) //记录接下来的词,每个词前有space
{
result[result_len++] = ' ';
for(int j = space_indexs[i]; j > space_indexs[i -1]; j-- )
result[result_len++] = revers_str[j];
}
result[result_len] = '\0';
string ss(result);
str = ss; //返回值
}
解析:这个方案是三个方案中耗时最小的方案,通过一次遍历记录了每个词的分割位置,并将字符序列求逆。但现在想想貌似直接记录词的位置第二次逆序读取似乎可以更好。 Run time 12ms. 注意!!!我忘记delete了~
总结:
1. 关于格式,对空格要求比较多,所以输出时要格外小心。关于Output Limited,使用了引用传值,所以最后不用自己print,而是赋值回去。
2.关于RunTime Error,可能就是溢出,包括数组越界,递归栈溢出,数组下标为负,除以0等。在第三个方案中我开始忘记了对space_index[0]的初始化,直接导致后来有可能使用到为赋值的值,以后有东西了可以memset一下。开数组定义变量要想想不初始化的危险性。
3.关于new 和静态数组,我一直喜欢new,delete,结果还是忘记delete。还有就是其实静态数组在刷题和很多情况下都蛮有用的,省了很多new和delete的时间。有人提醒我说,全局的东西可以new,局部的就别再new了。
备注:由于还不会插入代码,所以代码格式是手动调的。。忍忍吧~~o(╯□╰)o