
面試官
自來也
去掉一個字符串中的空格。
假設用C語言來解答,字符串是char數組。O(n)時間復雜度實現不難,比如額外申請一個新數組,然后遍歷一遍字符串,將符合條件的字符存儲到新數組中,實現起來很簡單。
但這顯然不能讓面試官滿意。其實可以不開辟新數組空間實現。用兩個變量i,j做游標,從前向后遍歷。也算是算法題中“雙指針”解法的一種題型了。
char s[] = "1 2 3 4 5"; int sz = strlen(s); int i = 0, j = 0; for (; j < sz; j++) { if (s[j] != ' ') { s[i] = s[j]; i++; } } s[i] = '\0';
題目二

面試官
自來也
一個整數數組,將0排到前面,非0在后,非0的相對順序不變。
本題和上一題思路相同,只是兩個游標從后向前。另外注意最后不要忘記給數組頭部的元素設置0。
int num[] = {1, 0, 0, 3, 0, 0, 0, 4, 5, 0, 2}; int n = sizeof(num)/sizeof(int); int i = n - 1, j = n - 1; for (; j >= 0; j--) { if (num[j] != 0) { num[i] = num[j]; i--; } } for (; i >= 0 ; i--) { num[i] = 0; }
這兩個面試題其實也是工作中針對數組、鏈表的一種常見操作的簡易表達。有時候我們從線性容器中刪除元素,當時只是打上一個標記,并未真正刪除,也未改變容器結構。在后面一個適當的時候,做一次處理,一次性批量地剔除本已刪除的元素。彼時這個操作便是『compact』,或翻譯成『緊湊』操作。
說開來

面試官
自來也
其實這個假刪除,后來再compact的操作,在STL中早有體現,你了解嗎?
C++ STL中的算法函數std::remove()便是如此,用remove來刪除vector中元素時,它不會真的移除元素,它既不改變end()迭代器,也不改變成員函數size()、capacity()的值!而且它不是將待刪除元素交換到末尾,其只是做單向復制,比如vector 存儲{0,1,0,3,12} 使用remove算法刪除0后則是 {1,3,12,3,12}。最后兩個元素3和12其實已然多余。
如果想要真的刪除需要借助vector成員函數erase()。std::remove()執行完畢會返回一個迭代器,該迭代器指向首個被復制到尾部的元素的位置,也就是從這個位置到vector的end(),都是無效的元素,可被刪除!
vector<int>?v;// 刪除0v.erase(remove(v.begin(), v.end(), 0), v.end());
std::remove()也可以操作list容器,效果同vector,也不是真實刪除。但list其實提供了成員函數list::remove(),可以做刪除操作,且是真實刪除。另外list也有list::erase()成員函數.對于list而言,list::remove()和list::erase()的區別是:
remove()接收的參數是元素的值,而erase()接收的是迭代器,這點和vector相同。
關聯容器(比如map)其刪除函數的也名為erase(),接收迭代器參數,也是真實刪除。
你會發現STL中erase()都是按迭代器來做刪除(vector、list、map都有erase()成員函數),而remove()是按值刪除(list成員函數或std::remove())。
注意,如果在for循環中做順序容器的刪除操作,那么for循環的括號中,就不要做迭代器的累加操作了。這樣很容易出問題,一般把迭代器的累加操作放到循環體中。