沒錯,今天又是做簡單題的一天。
給定一個僅包含大小寫字母和空格
' '
的字符串,返回其最後一個單詞的長度。如果不存在最後一個單詞,請返回 0。
看到這個題目,我的第一反應是雙指針,快指針指向數組最後一個的時候,減掉停在最後一個' '
上的慢指針,就能得到長度了。但是想想覺得用指針還不如直接計數來得實在,而且這樣做存在一個問題,如果是類似於" a "
這種的字符串,就需要保存之前的狀態,所以還需要額外的空間來存儲之前的狀態,類似於dp。於是出來了這麼一個醜陋的解法:
int lengthOfLastWord(string s)
{
auto length = s.length();
int count = 0;
vector<int> vec;
for (auto i = 0; i < length; ++i)
{
if (s[i] != ' ')
{
++count;
}
else
{
vec.push_back(count);
count = 0;
}
}
vec.push_back(count);
auto n = vec.size();
int res = vec[n - 1];
if (res)
{
return res;
}
else
{
for (int i = n - 1; i >= 0; --i)
{
if (vec[i])
{
return vec[i];
}
}
return 0;
}
}
估計是因爲測試數據不大,結果居然還可以。但是我注意到了一件事,爲什麼非得正着數而不倒着數……明明倒着數效果更好,找第一個肯定比找最後一個簡單。
同時,我還意識到,之前導致存儲狀態的罪魁禍首就是兩邊的空格,把空格去掉不就好了……所以又加了一個trim的函數。因爲倒着數,所以去掉右邊的空格就可以了。當然,trim不是我寫的:
// trim from end (in place)
static inline void rtrim(std::string &s)
{
s.erase(std::find_if(s.rbegin(), s.rend(),
std::not1(std::ptr_fun<int, int>(std::isspace)))
.base(),
s.end());
}
int lengthOfLastWord(string s)
{
rtrim(s);
int start = s.length() - 1;
int i = start;
for (; i >= 0; --i)
{
if (s[i] == ' ')
{
break;
}
}
return start - i;
}
這樣明顯好一點。
至於加一這個題目,本來不想做的,但是看到和之前寫的NASM的思路很像,忍不住就隨手寫了一下。主要就是三種情況吧,第一種不進位,第二種非最高位的進位,第三種是最高位的進位(比如999 + 1 = 1000)。思路很簡單,模擬一個加法器就行了:
vector<int> plusOne(vector<int> &digits)
{
int length = digits.size();
bool carry = true;
for (int i = length - 1; i >= 0; --i)
{
if (carry)
{
++digits[i];
carry = false;
}
if (digits[i] >= 10)
{
digits[i] -= 10;
carry = true;
}
else
{
break;
}
}
if (carry)
{
// 這裏確實比使用insert要好
digits[0] = 1;
digits.push_back(0);
}
return digits;
}
但是有一點很有意思,我在處理最高位進位的時候使用了vector的insert方法。我們知道,vector在處理非尾部的insert的時候是很無力的。但是我看到某位dalao的解法裏是這樣寫的:
digits[0] = 1;
digits.push_back(0);
在這個場景下,可以說是神來之筆了。在最後加一個0,然後把第一位改成1,和在最前面加一個1的效果是相同的,但是減小了開銷(少了一個移動元素的過程)。這個寫法的複雜度是O(1),而用insert的複雜度是O(m),高下立判。