KT 的 Python 進階程式設計

W05|先記住目前冠軍:最大值與最小值

今天完成後,我可以

  1. 每讀入一筆資料,就判斷是否需要更新目前的最大值或最小值。
  2. 根據題目條件,選擇第一筆真實資料或範圍外數值作為起始值。
  3. 找到極值時,也能同步記錄它的位置或其他相關資訊。

本週練習極值的更新過程,不使用max()、min()、sorted()、sort()或串列保存全部資料。

一、教師示範與課中跟做

1-1|b019 誰是學霸(50分)

題目會逐行輸入全班成績,請找出最高分。先看題目的輸入與輸出,再跟著教師一起解題。

開始前先想一想:如果班上只有3位同學,你會怎麼找最高分?如果變成40位,原來的方法還適合嗎?

看教師示範時,只要追蹤四個問題:

  1. max_score現在保存的是什麼?
  2. max_score的初始值應該設定為多少?這個值從哪裡來?
  3. 第一筆已經讀入後,迴圈應執行n次還是n - 1次?
  4. 讀到更高成績時,應該寫max_score = score還是相反?

示範結束後,請關閉示範畫面,自己重新輸入、測試並提交。本題不使用串列、max()或排序功能。

需要時展開:挖空程式碼骨架
Python 3圖片

四個空格分別在處理:初始值、迴圈範圍、比較條件與更新動作。請先說明每一格的任務,再填入程式碼。

解完b019再整理:這題用到的三個觀念
  • 每讀到一筆新成績,就讓它挑戰「目前最高分」。
  • 第一筆已先成為目前最高分,所以後面只剩n - 1筆。
  • 要更新紀錄時,把新成績放進max_score;等號方向不能寫反。

處理完每一筆資料後,max_score都應代表「目前已看過成績中的最高分」。

延伸思考:迴圈裡的數字能不能代表座號?

第一位同學的成績已經先讀入,因此剩下要處理的是第2位到第n位同學:

Python 3圖片

請觀察:student_number第一次與最後一次分別是多少?它們各代表哪一位同學?

b019只要求最高分,所以暫時不需要使用這個座號。如果下一題還要回答「最高分是第幾位同學」,這個變數可以怎麼幫忙?

二、課中獨立練習

2-1|b024 低空飛過(50分)

這題不是從全部成績找最低分,而是只從及格成績中尋找。

題目中的成績範圍是0~100。因為101不可能是真正成績,可以先把它當成「目前還沒有找到及格者」的暫時記號。

這和b019的初始化方式不同:

處理每筆成績時,分成兩個問題思考:

  1. 這筆成績是否及格?
  2. 及格後,它是否比目前最低及格分更低?

初次撰寫時,可以先使用兩層if表達「先取得資格,再挑戰紀錄」,不用急著把兩個條件合併。

縮排形狀可以先寫成:

資料/示意
if 第一個條件:
    if 第二個條件:
        要做的事
提示一:利用範圍外的暫時記號

先將目前最低及格分設為101。第一筆及格成績一定小於101,因此會自然取代暫時記號。

提示二:最後如何知道沒有人及格?

全部成績處理完成後,如果目前最低及格分仍是101,表示沒有任何及格成績,應依題意輸出QQ。

補救練習:如果基本最小值更新還不熟

可以先完成a377精打細算,再回來訂正b024。這是需要時使用的補救題,不是本週正式課後作業。

三、解題後整理

極值不只是一個數字

有些題目除了極值,還會問極值出現在哪個座號。找到更好的資料時,極值與座號必須一起更新,否則可能得到「正確的最高分,卻配上錯誤的座號」。

迴圈變數不一定叫i

如果迴圈只負責重複固定次數,可以使用i。如果迴圈中的數字代表座號、天數或年份,就改用student_number、day或year等能說明身分的名稱。

四、課後挑戰

表格可左右滑動
題目 配分 定位 本週目標
b021 誰是學霸之到底是誰 40分 核心應用 找最大值時同步記錄座號,並保留較早的最高分者
a102 叢林小松鼠2 30分 選做挑戰一 不排序、不保存全部資料,嘗試維護目前前三大值
c071 遊戲選角 30分 選做挑戰二(APCS) 找第二大的能力值,並保留該角色的攻擊力與防禦力

4-1|b021 誰是學霸之到底是誰(40分)

已知成績範圍為0~100,可以用-1表示「目前還沒有最高分」。這次迴圈中的數字就是學生座號,因此使用student_number會比i更容易閱讀。

提示:分數與座號要一起更新
Python 3圖片

題目要求同分時保留座號較小者,因此請思考比較時應使用>還是>=。

完成後整理:同分時要留下誰?

如果只在新成績>目前最高分時更新,同分時不更新,會保留較早出現者;如果使用>=,同分時也會更新,最後會留下較晚出現者。

這不是固定背誦規則;仍要先讀清楚題目要求留下最早或最晚出現者。

4-2|a102 叢林小松鼠2(選做,30分)

這次要選出前三重的果實並計算總重量。可以準備三個變數,分別保存目前第一大、第二大與第三大。

最大的挑戰不是比較,而是更新順序:當新的第一大出現時,原本的第一大與第二大應該移到哪裡?

思考步驟
新的第一大出現
→ 原本第二大移到第三大
→ 原本第一大移到第二大
→ 新資料放入第一大

為什麼移動時要從第三名的位置開始處理,而不能先覆蓋第一名?請用三個不同數字追蹤一次再開始寫程式。

本題是進階選做,不列入本週基本完成要求。

4-3|c071 遊戲選角(APCS選做,30分)

完成a102後再挑戰這題。每位角色的比較依據不是單一輸入值,而是由攻擊力與防禦力算出的能力值;最後輸出的卻是該角色原本的攻擊力與防禦力。

先以只有三位角色的情況思考:除了記住目前第一大與第二大的能力值,哪些原始資料也必須跟著移動?

本題的60%子題只有三位角色。即使暫時無法完成一般情況,也可以先完成這個版本。

每行的攻擊力與防禦力是兩個以空白分隔的數字,可查閱輸入輸出技巧|同一行有固定數量的資料;輸出兩個數字時可查閱同一行使用空白分隔。能力值的平方可使用**。

五、完成後自我檢查

六、超前挑戰題單

本區自由選做,不計入W05課中或課後配分,也不需要全部完成。請先完成本週正式題目,再從感興趣的題目選一題挑戰;如果暫時卡住,可以把問題記下來,之後學到更多工具再回來完成。

開始挑戰前:先將隨堂練習交卷

JMJ進行隨堂練習時,不能直接前往練習以外的題目。完成本週必做題後,請依照下列順序操作:

  1. 確認必做題都已經送出,並檢查目前得到的分數。
  2. 回到這次隨堂練習的「題目列表」,向下捲到題目下方。
  3. 依老師指示,按下左下角綠色的「做完交卷(交卷之後將無法再進入)」按鈕。
  4. 確認完成交卷後,再回到本頁點選下方題名;題目會在新的分頁開啟。

注意:按下「做完交卷」後就無法再次進入這份隨堂練習。還想繼續修改必做題時,不要提早交卷;不確定時先詢問老師。

表格可左右滑動
建議順序 題目 可以練到什麼 挑戰限制
1 a071 這就是我們之間的差距! 同時維護最大值與最小值,再計算兩者差距 不使用max()、min()、排序或串列
2 a148 捕魚(Fishing) 找最接近的目標,並讓座標與目前最佳值一起更新 不使用串列與min();可以比較距離的平方
3 a064 最大公因數 用窮舉、取餘數與變數更新保留最後一個共同因數 不使用math.gcd()
4 a040 文文的求婚(三) 複合條件、範圍迴圈與計數 逐年判斷,不直接套用閏年數量公式
5 a150 躲避球(Dodgeball) 依事件逐步更新目前狀態 每處理一筆事件,就立即更新一次結果
6 a149 計程車(Taxi) 把較長的規則拆成條件、計算與加總 先分段列出規則,再開始寫程式

完成一題後,請確認自己能不看別人的程式,說明「每個變數保存什麼」以及「每一圈做了什麼」。