LeetCode系列字串操作(一)ZigZag輸出,尋找最大不重複字串長度。
ZigZag Conversion
The string "PAYPALISHIRING"
is written in a zigzag pattern on a given number
of rows like this: (you may want to display this pattern in a fixed font for better legibility)
P A H N A P L S I I G Y I RAnd then read line by line:
"PAHNAPLSIIGYIR"
Write the code that will take a string and make this conversion given a number of rows:
string convert(string text, int nRows);
convert("PAYPALISHIRING", 3)
should
return "PAHNAPLSIIGYIR"
.
分析; 此題是將一個正常的string序列用ZigZag的形式進行表示,zigzag在英文裡是曲折的意思,即以鋸齒狀的形式將字元重新排列。此題如果很清楚這個ZigZag的形狀的話是道容易的題,但是如果不知道可能就會吃虧。
這道題我大概提交了三次,因為剛開始不是很清楚這個鋸齒到底是怎麼一個形狀,我以為沒兩個長列中間就只有一個元素,就如同上面的題目給出的那種形式,那麼現在問題是,這個中間的一個元素位於第幾行呢? 我剛開始就預設是在第二行,提交了一次,錯誤。然後我根據測試用例的期望值認為這個元素在倒數第二行,又提交了一次,結果還是錯誤。最後無奈我到網上搜索了一下該形狀到底如何,最後才表白每兩個長列之間是一個對角線,構成一個正方形。如下圖所示:
所以很容易發現下面的規律:
對於nRows大於1的話。
1) 對於第一行和倒數第一行,後一列的元素對應的原字串中的位置是前一列的元素+(nRows-1)*2;
2) 對於中間的行(當行數大於2的時候),如果當前列是偶數列(從0開始),那麼那是奇數列的位置+(nRows-1-i)*2.如對於第二行,
第1列的Index=1+(4-1-1)*2 = 5. 而偶數列是前一列的index + 2*當前行。
上面的規律稍加推導即可得出。
下面是程式碼:
string convert(string s, int nRows) { string temp(s); if (nRows < 2) return temp; int i, step; int j = 0; int count; for (int row = 0; row < nRows; row++) { if (row == 0 || row == nRows - 1) { step = (nRows - 1) * 2; for (i = row; i < s.size(); i = i + step) { temp[j++] = s[i]; } } else // 對於從正數第二行到倒數第二行 { count = 0; for (i = row; i < s.size(); i = i + step) { temp[j++] = s[i]; if (++count & 0x01) step = row*2; //偶數列 else step = (nRows - 1 - row) * 2; //奇數列 } } } return temp; }
Longest Substring Without Repeating Characters
Given a string, find the length of the longest substring without repeating characters. For example, the longest substring without repeating letters for "abcabcbb" is "abc", which the length is 3. For "bbbbb" the longest substring is "b", with the length of 1.這道題剛開始做的時候思路還是很清晰的,兩個指標分別向後,然後將每一個字元和set中的元素進行比較,如果是沒有出現過那麼放入set並將長度加1.這種方法簡單是比較簡單,但是時空複雜度都比較高,其中時間複雜是o(n^2),空間複雜度也有o(n),最後提交的時候果然超出時間限制。
下面給出一種網上比較流行的用時間換空間的做法:
用一個數組hash_charc儲存所有可能出現的字元在最近一次出現的位置。兩個index用來控制遍歷,其中一個i用來遍歷所有的字元,cur用來
儲存當前未測試的,有效的子串開始的位置。
如果當前的字元在這個cur之後沒有出現過,計算一下dis看是否要更新這個最大值。
如果出現過了,那麼,計算這兩個相同的字元之間的距離看是否要更新最大距離值。同時更新cur為之前出現的字元的位置。
下面是用c++實現的程式。
int lengthOfLongestSubstring(string s) {
int hash_char[256];//儲存字元上一次出現的位置
memset(hash_char, -1, sizeof(hash_char));
int curr = -1, max = 0;
for (int i = 0; i < s.size(); i++)
{
if (hash_char[s[i]] > curr)//如果當前字元在curr之後出現過,更新curr為上一次出現的位置
curr = hash_char[s[i]];
max = max > i - curr ? max : i - curr; //注意這個步驟不管上面的if是否滿足都會做。
hash_char[s[i]] = i;
}
return max;
}