請將方法補充完整:
復制代碼 代碼如下:
static void Reverse(int[] array, int begin, int end)
{
...
}
Reverse方法的作用是將array數組中,從begin下標到end下標之間的元素反序一下,如一個數組初始值是[1, 2, 3, 4, 5, 6],begin為1,end為4,那麼當調用了Reverse之後,array數組中的元素便依次成為[1, 5, 4, 3, 2, 6],其中從array[1]到array[4]之前的元素被反序了。此外補充一點……其實本不用補充:這個方法需要對傳入參數的正確性進行校驗,如果用戶調用該方法時傳入了非法的參數,那麼則需要拋出異常,並寫清原因。您可以使用您喜歡的語言來實現:C#,VB,Java,Ruby,Python……但是請不要使用內置庫中已經有的功能。:)
很簡單,不是嗎?只可惜截止到目前,也只有1人給出了正確答案。如果您沒有做過這道題目,那麼在查看下面的分析之前,不妨拿張紙拿支筆,寫下您的答案,然後再聽老趙慢慢講來…
主體邏輯
這道題目的主題邏輯其實非常簡單。不就是把數組中的一部分反序嗎?不過從這一點上面來說,代碼的清晰程度也有較大差距。好的做法和普通的做法,從編程難度和理解上都有一定差距。例如:
1、許多朋友的做法是:既然是反轉數組的一部分元素,那麼只要找到中間的位置,然後計算出和begin的偏移量,然後……怎麼怎麼一搞,就完成了——嗯,似乎還需要根據進行begin和end中間的元素個數是奇數還是偶數分別處理。
2、另一些朋友的做法是:開一個新數組(長度為end - begin + 1),將begin到end之間的元素放到新數組中去,然後反序,然後再復制回來。
3、還有一個朋友認為用棧:把begin到end之間的元素給push到棧中,再一個一個pop出來依次賦值給begin到end,這樣就反序了……唔!數據結構學的不錯!
只可惜,這樣的做法都復雜了一些。3種做法的時間復雜度均為O(end – begin),但是只有第一種做法的空間復雜度是O(1),而後兩者也都是線性的空間復雜度。那麼老趙眼裡最好的做法是什麼呢?
復制代碼 代碼如下:
public static void Reverse(int[] array, int begin, int end)
{
while (end > begin)
{
int temp = array[begin];
array[begin] = array[end];
array[end] = temp;
begin++;
end--;
}
}
end和begin兩個下標從初始值開始依次向中間逼近,每次都交換一下數組中的元素。最終,while在判斷的時候會發現end == begin(begin和end之間總共奇數個元素),或end < begin(begin和end之間總共偶數個元素)。無論哪種情況,都表示反序已經完成。
參數校驗 上面的做法應該說是最簡單的一種,不過實際在評判答案的時候,直接結果正確,老趙都認為是正確的。只可惜,幾乎沒有朋友在“參數校驗”這方面作對。
順便提一下的是,有位朋友給我留言很有意思:“老師只給了一個測試數據,如果要用其它測試數據的話比如比較特殊的,那請老師下次把測試數據列好。”這句話讓我木然:測試數據是無窮無盡的,難道需要都列出來?平時寫程序,用戶會指出他的所有操作步驟嗎?給測試數據的目的是為了幫助理解題意,題目的要求都寫清楚了,做題才有意義。如果一道題目只要求把給出的測試數據運行,那麼又有誰不會做呢?老趙這裡就可以立即給出一個萬能模板:
復制代碼 代碼如下:
if (...)
{
return ...
}
else if (...)
{
return ...
}
...
按理來說,即使題目中沒有寫明需要參數校驗,一個優秀的實現也應該自帶這一點。
其實只要仔細一些,把參數所有的錯誤情況列舉出來並不是難事:
復制代碼 代碼如下:
1、array == null
2、begin < 0;
3、end < begin
4、end >= array.Length
那麼,其他一些情況是否應該一並判斷呢?例如end < 0,array.Length == 0或者begin >= length。老趙認為“不判斷也沒有關系”,因為以上的判斷已經確保不會出現額外的錯誤情況了。那麼begin == end是否算是問題呢?老趙認為,這個判斷也可以省略。不過……如果begin > end,那麼是否應該把兩者的數值進行交換?我不知道為什麼有些朋友這麼做了,不過老趙認為,一般來說一個方法不應該為參數進行額外“調整”——其實各大類庫都不會如此畫蛇添足。如果哪位朋友有不同看法,我們可以繼續討論。
當前1/2頁
12下一頁閱讀全文