今天開始在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