《演算法設計與分析》第二週作業
《演算法設計與分析》第二週作業
標籤(空格分隔): 課堂作業
姓名:李**
學號:16340114
題目:ZigZag Conversion(https://leetcode.com/problems/zigzag-conversion/description/)
題目概要
輸入一個字串,將該字串按類z形狀排列,再按橫向順序輸出新的字串,詳情點選題目連結。
思路
嘗試一
建立一個矩陣,把輸入字串按照題目規則填入矩陣中,矩陣剩餘位置留空,再按行遍歷矩陣,得到目的輸出。這樣做貌似很暴力,而且當行數增多的時候,矩陣裡的空位會變得很多,且遍歷的開銷也會變得非常大。這種解法似乎不現實。
嘗試二
採用分而治之的思想,將按z型排列的字串分成若干個相同的組(如圖所示),在一個組內建立輸入字串與輸出字串的對映函式,繼而推廣到所有組別,得出通用的轉換公式。
注意到,在分組的時候,最後一組可能與其他組不同,這使得對映函式的建立變得困難,因此,先假定最後一組與其他組的模式都是相同的,之後再處理最後一組(參差不齊)的問題。
在建立轉換公式之前,先計算一些重要的引數:
每組的字元個數(靠觀察可得):entitiesInSet = 2 * numRows - 2;
總組數(同樣靠觀察可得):numSet = ⌈ inputString.length() / entitiesInSet ⌉(向上取整);
在每一組中,分為四種情況:
1.組內第一個字元
稍微觀察一下(感覺這題就是在找規律),每組的第一個字元對應輸出字元下標為 分組序號setIndex,即
outputString[setIndex] = inputString[oldStringIndex];
2.組內第一列中間字元(除去第一個和最後一個字元)
第二行的元素對應的下標為 【第一行的字元數 + 組號 * 2】
第三行的元素對應的下標為 【第一行的字元數 + 第二行的字元數 + 組號 * 2】
···
第i行的元素對應的下標為 【第一行的字元數 + 第二行的字元數 + ··· + 第i - 1行的字元數 + 組號 * 2】
第一行的字元數為總組數numSet,剩餘行的字元數為總組數乘二numSet * 2。
可以得到對第一列中第i個(對應第i+1行)字元。(圖中第一組的A是第1個(i = 1),Y是第二個 (i = 2))對應的下標為 【組數 * (2 * i - 1) + 組號 * 2】, 即
outputString[numSet * (2 * i - 1) + setIndex * 2] = inputString[oldStringIndex];
3.組內第一列最後一個字元
用類似情況2的推算,對應的下標為 【除最後一行的總字元數(第一行的字元數 + 第2行 ~ 第numRows - 1行)的字元數 + 組號】,即
outputString[numSet * (2 * numRows - 3) + setIndex] = inputString[oldStringIndex];
4.組內在斜線上的元素
與第2中情況類似,只是對應的下標多了1,組數 * (2 * i - 1) + 組號 * 2 + 1,即
outputString[numSet * (2 * i - 1) + setIndex * 2 + 1] = inputString[oldStringIndex];
這四種情況都處理完之後,就開始處理最後一組(參差不齊)的問題。
其實這個問題還蠻好處理的,將最後一組單獨拿出來處理,先假定最後一組是完整的,與其他組一樣處理,在遇到輸入字元不存在的位置時,將一個特殊符號(如“*”,輸入字串裡沒有該符號)放入輸出字串中。將全部完成後再次遍歷輸出字元,遇到該特殊字元(*)時將該字元剔除,即可得到最終答案。
具體實現
先計算“思路”中的兩個重要引數。
再以組號為引數進行迴圈,處理除最後一組之外的組。同時使用一個下標變數,按順序對輸入字元進行處理,每處理完一個字元該變數自增。
在每組中按照思路中的4種情況按順序處理,將得出的公式轉化為程式碼即可,特別地,在第3種情況中,隨著輸入字元下標的遞增,行數是遞減的,這時只要將迴圈變數遞減即可。
之後處理最後一組,使用巨集定義檢測下標是否越界,如越界,則將‘*’輸出到輸出字串。
最後建立一個新的字串,將中間輸出字串的非’*’字元吸收即可。
心得
雖然這次沒用到課堂上講的大師定理,但是分治思想的應用還是使得這個問題簡單了許多(比用矩陣蠻幹好多了不是嗎),將一個大問題分解成一個個的小問題,這樣思考起來不會那麼吃力,而且把小問題解決了大問題也就自然而然地就解決了。
原始碼:
#define entityOrBubble (oldStringIndex >= s.length() ? '*' : s[oldStringIndex]);
class Solution
{
public:
string convert(string s, int numRows)
{
if (s.length() == 0 || numRows == 1)
return s;
int entitiesInSet = 2 * numRows - 2;
int numSet = ceil( (float)s.length() / entitiesInSet );
string tempString(numSet * entitiesInSet, '*');
// common set
for (int setIndex = 0; setIndex <= numSet - 2; ++setIndex)
{
int oldStringIndex = setIndex * entitiesInSet;
//first entity in each set
tempString[setIndex] = s[oldStringIndex];
oldStringIndex++;
//the remain entities of the first column in each set except the last one
for (int i = 1; i <= numRows - 2; ++i)
{
tempString[numSet * (2 * i - 1) + setIndex * 2] = s[oldStringIndex];
oldStringIndex++;
}
//the last entity of the first column in each set
tempString[numSet * (2 * numRows - 3) + setIndex] = s[oldStringIndex];
oldStringIndex++;
//the remain entities of each set
for (int i = numRows - 2; i >= 1; --i)
{
tempString[numSet * (2 * i - 1) + setIndex * 2 + 1] = s[oldStringIndex];
oldStringIndex++;
}
}
// the last set
{
int setIndex = numSet - 1;
int oldStringIndex = setIndex * entitiesInSet;
//first entity in each set
tempString[setIndex] = s[oldStringIndex];
oldStringIndex++;
//the remain entities of the first column in each set except the last one
for (int i = 1; i <= numRows - 2; ++i)
{
tempString[numSet * (2 * i - 1) + setIndex * 2] = entityOrBubble;
oldStringIndex++;
}
//the last entity of the first column in each set
tempString[numSet * (2 * numRows - 3) + setIndex] = entityOrBubble;
oldStringIndex++;
//the remain entities of each set
for (int i = numRows - 2; i >= 1; --i)
{
tempString[numSet * (2 * i - 1) + setIndex * 2 + 1] = entityOrBubble;
oldStringIndex++;
}
}
string finalString(tempString.length() + 1, '\0');
int finalStringIndex = 0;
for (int i = 0; i < tempString.length(); ++i)
{
if(tempString[i] != '*')
{
finalString[finalStringIndex] = tempString[i];
finalStringIndex++;
}
}
return finalString;
}
};