【筆者感悟】筆者的學習感悟【十】

2023-10-31 15:00:34

寫在前面

  今天筆者想來和大家討論一下,刷演演算法題的一些心得

  說到演演算法題想必很多同學都會有許許多多的討論,有的同學認為刷演演算法題是必修課,有的同學認為演演算法不實用,工作中用不到。

  那麼筆者的態度是什麼,以前其實已經說過了,還是那句話:必須刷

  至於為什麼,後面會解釋,並且筆者還會和大家討論如何把題目刷好

實質分析

  拋開事實談邏輯那叫耍流氓,因此筆者就先冒犯一下,把大家當做傻瓜,拿一道題來做個演示,我們在刷題過程中到底在做些什麼

將一個給定字串 s 根據給定的行數 numRows ,以從上往下、從左到右進行 Z 字形排列。

比如輸入字串為 "PAYPALISHIRING" 行數為 3 時,排列如下:

P   A   H   N
A P L S I I G
Y   I   R
之後,你的輸出需要從左往右逐行讀取,產生出一個新的字串,比如:"PAHNAPLSIIGYIR"。

請你實現這個將字串進行指定行數變換的函數:

string convert(string s, int numRows);
範例 1:

輸入:s = "PAYPALISHIRING", numRows = 3
輸出:"PAHNAPLSIIGYIR"
範例 2:

輸入:s = "PAYPALISHIRING", numRows = 4
輸出:"PINALSIGYAHRPI"
解釋:
P     I    N
A   L S  I G
Y A   H R
P     I
範例 3:

輸入:s = "A", numRows = 1
輸出:"A"
提示:

1 <= s.length <= 1000
s 由英文字母(小寫和大寫)、',' 和 '.' 組成
1 <= numRows <= 1000

第一步:審題

  同學們在思考這道題的時候,腦海裡是不是會出現以下內容

  這道題可以通過模擬Z字形排列的過程來解決。我們可以使用一個二維陣列來表示Z字形排列的結果,然後按照從上到下、從左到右的順序將字串中的字元填入二維陣列中。最後,按照從左到右、從上到下的順序讀取二維陣列中的字元,得到最終的結果字串。

  大家看看題目這個東西有半點技術嘛?很明顯沒有,那麼在整個軟體工程中,唯一重要,但是文字字裡行間不會涉及到技術的東西是啥,沒錯就是需求,同學們發現沒有,大家審題的時候是不是相當於我們在做需求分析。我們到底要具體實現一些什麼東西,是不是這個時候都要分析出來

第二步:分析

  然後我們接下來刷題的時候會怎麼做?是不是同學們腦海中會出現以下內容

  1. 如果 numRows 為 1,直接返回原字串 s。
  2. 建立一個 numRows 行的二維陣列,用於儲存 Z 字形排列的結果。
  3. 初始化當前行和當前列為 0,表示當前要填入的位置。
  4. 遍歷字串 s 中的每個字元:
    • 將當前字元填入二維陣列的當前位置。
    • 如果當前行小於 numRows-1,表示還可以向下移動一行,將當前行加 1。
    • 否則,表示已經到達 Z 字形的底部,需要向上移動一行,將當前行減 1,同時當前列加 1。
  5. 按照從左到右、從上到下的順序讀取二維陣列中的字元,得到最終的結果字串。

  時間複雜度分析:遍歷字串 s 的時間複雜度是 O(n),其中 n 是字串的長度。最後按照從左到右、從上到下的順序讀取二維陣列中的字元的時間複雜度也是 O(n)。因此,總的時間複雜度是 O(n)。

  空間複雜度分析:建立二維陣列的空間複雜度是 O(numRows * n),其中 numRows 是行數,n 是字串的長度。最後返回的結果字串的空間複雜度是 O(n)。因此,總的空間複雜度是 O(numRows * n)。

  

  同學們發現沒有,我們在敲程式碼前,需要幹什麼,對,到底要怎麼實現需求,我們腦海中需要有一個大致的步驟,先做什麼後做什麼,需要很清楚,這像不像軟體工程中的設計階段

第三步:編碼

  這一步我想是大家最熟悉的階段,筆者就不再過多闡述了,但是筆者這裡還想再次強調一下,包括之前不止一次強調過,敲程式碼這項工作大約只佔整個軟體工程中的兩到三成,現在我想大家應該又能夠有點感受了吧,很多同學為什麼覺得敲程式碼痛苦地不得了,因為同學,你把很多前面應該做的事,全部都省略了,編碼階段負責給你前面的偷懶來擦屁股,你當然會覺得痛苦萬分。筆者還是那句話,你只會編碼,你不叫工程師,你叫程式設計師。

  編碼階段要做的事情只有一個,就是利用你腦中的程式設計知識,巧妙地實現你前面的分析和設計,這個階段要想做好,你要做的事情只有一件,就只是對你在用的程式碼很熟悉,就可以了

  事實上分析和設計都是需要單獨練的,很多同學從來沒有系統練過,只是一味地敲程式碼,這樣不成體系的混亂學習,那怎麼會有明顯的長進呢。

第四步:偵錯

  往往做好題目以後,會出現各種各樣的問題,除了AC會有很多讓我們心態爆炸的結果,最典型的就是以下這些

  • CE(Compile Error):編譯錯誤。
    • 你的程式存在語法錯誤(C / C++ 最常見的是缺少分號、缺少括號、使用了中文標點符號或者函數呼叫錯誤等等)或者OJ系統不支援的寫法(較少見)。
    • 此時應當仔細檢查程式碼在本機能否通過編譯,改正後再次提交。
  • PE(Presentation Error):輸出格式錯誤。
    • 你的程式幾乎能AC了,但是和標準輸出資料有點細微的差距(大小寫,空格數量,換行數量之類的)。
    • 此時應當仔細觀察題目給出的輸出樣例,確認格式無誤(選中資料貼上到編輯器最為穩妥)。
  • WA(Wrong Answer):答案錯誤。
    • 你程式輸出的結果有錯誤,與期望輸出不匹配(也有可能是因為缺少了必要的換行和空格)。
    • 請檢查你的程式是否出現了致命的邏輯錯誤,當然有的時候是因為手滑。
  • TLE(Time Limit Exceed):超出執行時間限制。
    • 你的程式可能因為時間效率不高或者出現了死迴圈,所以未能在規定的時限內執行結束。
  • MLE(Memory Limit Exceed):超出執行記憶體限制。
    • 你的程式佔用的記憶體超過了規定值,可能是因為使用了過大的陣列,也可能是沒有做到記憶體釋放(較少見)

  這個時候我們一般看到這樣的結果我們就需要幹什麼?沒錯,修改程式碼中的細節,甚至是整個思路錯了,要重新設計程式碼,有時候看測試樣例的時候,我們甚至都會罵街,出題人為什麼會給出這麼奇怪的測試案例

  已經工作的同學們,或者是已經從老師口中對工作有些許瞭解的同學,試著想想看開發人員和測試人員相愛相殺的畫面,再看看現在這個畫面,是不是很像,沒錯,我們一步步邁向AC的過程是在幹什麼,相當於軟體工程中的運維測試。

小結

  所以,同學們發現了沒有,我們在做演演算法題的時候,一道中等難度的題目,大約十幾分鍾到半個小時的過程,我們已經進行了一個簡易的軟體工程過程,這也就解釋了為啥很多廠,對應屆生的似乎演算法佔比很高,現在大家應該明白了吧,因為應屆生的專案經驗比較少,但是他演演算法題刷得多,一定程度上就彌補了他對整個工程認知不足的問題。至少軟體工程,在他的腦海裡形成了一個雛形。公司只要稍加培養,很快就能上手幹活。

  另外也解釋了有些同學強調實習,強調專案經驗,實際上也是一樣的道理,他已經有了足夠多的專案經驗,從技術到工程流程他都已經比較熟悉,自然不需要演演算法來彌補他的缺失。

演演算法本質

  肯定有同學要問了,你講到現在似乎沒扯到演演算法的內容,同學們,不要急。

  如果現在沒有演演算法這個概念,只是告訴你刷題,對於比較細心的同學,你們會怎麼做?沒錯,就是把大量的題目放在一起總結規律,把很多類似的問題放到一起總結共同的方法,甚至寫出共同的程式碼來,以後再遇到,就不用直接分析了,而是直接套用你手上已經總結好的東西,從而大幅加快速度。

  那麼,前輩們是很聰明的,他們已經幫你都總結好了,同學們平時學的演演算法和資料結構,就是在不斷地解決各種問題中總結出來的成果。

  所以,同學們現在明白了嗎,你學的演演算法和資料結構,就等同於是站在巨人的肩膀上,省時省力。但是大家還記不記得演演算法的概念是什麼,演演算法是一種用於解決問題或執行特定任務的有序步驟的描述。所以,這個東西是沒有止境的,同學們還要不斷地去總結。

切換語言

  很多同學可能都在頭疼學幾門語言的事情,有些同學學了語言沒有地方練習,那麼筆者的建議是什麼,在前面筆者也已經提到了,編碼階段要做的事情只有一個,就是利用你腦中的程式設計知識,巧妙地實現你前面的分析和設計,這個階段要想做好,你要做的事情只有一件,就只是對你在用的程式碼很熟悉,就可以了。

  所以,筆者給大家的建議是什麼,針對你已經分析過的題目,你換一個語言再試著去實現一遍,當然編碼和設計是相輔相成的,不同的語言可能在設計上會略有不同,但是如果都是物件導向的語言,基本上大體不會差到哪裡去。

  你只要解決,這個設計在你現在的語言中該怎麼實現的問題就可以了。

以後的路

  如果看到這篇文章的同學已經工作了四五年時間,那麼這個時候還要不要刷題呢,筆者的回答是,還得刷,筆者的理由有以下這些

【1】按照上面已經提到了,已經刷過的題目針對切換語言是很重要的,語言流不流行說實話我們說了不算,未來有啥新的語言,我們必須儘快掌握,否則很有可能就被淘汰了

【2】練習重要環節,刷題這件事情,某種程度上也是軟體工程,麻雀雖小五臟俱全。公司專案,拿到稱心專案的主動權不在我們手上,個人專案,提出好需求的難度也很高,而刷題這些幾千幾萬條需求,不拿來練習實在是太浪費的

附註

  那麼今天就和大家聊到這裡,希望筆者可以給大家帶來一些幫助,筆者接下來會更加努力的工作,給大家帶來更多的經驗分享,希望同學們工作順利,早日升職加薪、當上總經理、出任CEO、迎娶白富美、走上人生巔峰,想想是不是還有點小激動呢