用DP來精打細算 火車旅行支出的最小費用_Leetcode #983 最佳化DP應用

小松鼠
發佈於演算法專欄 個房間
閱讀時間約 9 分鐘

題目敘述 Minimum Cost For Tickets

題目會給定兩個陣列。
第一個是日期陣列days,代表外出旅遊的是哪幾天
第二個是成本陣列costs,代表火車一日票、七日票、30日的月票的票價

請問火車旅行支出的最小費用是多少?


測試範例

Example 1:

Input: days = [1,4,6,7,8,20], costs = [2,7,15]
Output: 11
Explanation: For example, here is one way to buy passes that lets you travel your travel plan:
On day 1, you bought a 1-day pass for costs[0] = $2, which covered day 1.
On day 3, you bought a 7-day pass for costs[1] = $7, which covered days 3, 4, ..., 9.
On day 20, you bought a 1-day pass for costs[0] = $2, which covered day 20.
In total, you spent $11 and covered all the days of your travel.

在第一天買一日票,可以覆蓋第一天。
在第三天​買七日票,可以覆蓋第三天~第九天,
在第20天買一日票,可以覆蓋第20天​

最小支出為 一日票 + 七日票 + 一日票 ​= 2+ 7+ 2= 11


Example 2:

Input: days = [1,2,3,4,5,6,7,8,9,10,30,31], costs = [2,7,15]
Output: 17
Explanation: For example, here is one way to buy passes that lets you travel your travel plan:
On day 1, you bought a 30-day pass for costs[2] = $15 which covered days 1, 2, ..., 30.
On day 31, you bought a 1-day pass for costs[0] = $2 which covered day 31.
In total, you spent $17 and covered all the days of your travel.

在第一天買30日票,可以覆蓋第一天~第三十天。
在第三十一天​買一日票,可以覆蓋第三​十一天,

最小支出為 30日票 + 一日票 ​= 15​元 + 2= 17

約束條件

Constraints:

  • 1 <= days.length <= 365

旅行日陣列長度介於1~365

  • 1 <= days[i] <= 365

每個旅行日一定是一年內的某一天。

  • days is in strictly increasing order.

旅行日嚴格遞增分布。

  • costs.length == 3

火車票價陣列長度為三,分別對應 一日票、七日票、30日票的價格。

  • 1 <= costs[i] <= 1000

車票價格介於1元~1000元之間。


觀察 所有選擇,挑一個費用最小的方案。

第一直覺可能會這樣想,那就都一口氣買30日的月票就好啦!

不過,一口氣買30日的月票並不是最佳解因為並不是每天都是出遊日。
根據出遊的情況,做出能夠覆蓋旅遊日期,同時兼顧支出費用最小才是正確的


假如我們今天要出遊,有那些選擇?

其實就是三種選擇

第一種是買一日票,只能覆蓋今天
第二種是買七日票,可以覆蓋最靠近的連續七天
第三種是買30日票(月票),可以覆蓋最靠近的連續三十天

我們要做的就是從這三種選擇裡面,
挑一個能夠盡量覆蓋出遊日期,又兼顧支出費用最小的選擇


示意圖

raw-image
raw-image
raw-image



演算法 DP動態規劃 + 可選擇的車票方案

1.定義DP狀態

承接觀察點的思考,定義DP[ day ] 代表從第一天 到 day這天的累積最小支出費用


最後所求是什麼?

就是全部旅行日的最小支出,DP[ days[-1] ]

也就是從第一天到最後一個旅行日的總支出最小費用


2.推導DP狀態轉移關係式

假如我們今天要出遊有那些選擇?

其實就是三種選擇,

第一種是買一日票,只能覆蓋今天
第二種是買七日票,可以覆蓋最靠近的連續七天
第三種是買30日票(月票),可以覆蓋最靠近的連續三十天


我們要做的就是從這三種選擇裡面,

挑一個能夠盡量覆蓋出遊日期,又兼顧支出費用最小的選擇

DP[ day ]
= min( 一日票 + DP[ day-1], 七日票 + DP[day-7], 30日票 + DP[ day-30] )


假如我們今天沒有出遊呢?

那也很簡單,沒有出遊,自然沒有支出費用,直接回溯檢查前一天day-1即可。

DP[ day ] = DP[ day - 1 ]

3.釐清DP初始狀態

最小規模的問題是什麼?

就是當回溯到旅行出發之前的時候,都還沒開始旅行,肯定沒有費用,支出=0

DP[ day ] = 0

程式碼 DP動態規劃 + 可選擇的車票方案

class Solution:
def mincostTickets(self, days: List[int], costs: List[int]) -> int:

# To speed-up travel day look-up, so make it a hashSet.
travel_days = set(days)

## DP table
# index: day
# value: minimal cost up to day so far
dp = {}

def travel(day):

# Look-up DP table
if day in dp:
return dp[day]

## Base case
# Before day_0, no traverl anymore, therefore no cost
if day <= 0:
return 0

## General cases:

# Not in travel day, just backtrack to previous day directly
elif day not in travel_days:
dp[day] = travel(day-1)
return dp[day]

# Today is travel day, pick the one which is of minimal cost
one_pass = travel(day-1) + costs[0]
seven_pass = travel(day-7) + costs[1]
monthly_pass = travel(day-30) + costs[2]

dp[day] = min( one_pass, seven_pass, monthly_pass)
return dp[day]

#-----------------------------------------------
return travel( day = days[-1] )

複雜度分析

令days陣列的長度為n

時間複雜度:O(n)

線性掃描每個旅行日,每個旅行日可以在O(1)內挑出最好的車票方案,總共耗時O(n)


空間複雜度:O(n)

DP table 和 travel_days集合 所需空間皆為O(n)


關鍵知識點 所有選擇,挑一個費用最小的方案。

假如我們今天要出遊有那些選擇?

其實就是三種選擇,

第一種是買一日票,只能覆蓋今天
第二種是買七日票,可以覆蓋最靠近的連續七天
第三種是買30日票(月票),可以覆蓋最靠近的連續三十天


我們要做的就是從這三種選擇裡面,

挑一個能夠盡量覆蓋出遊日期,又兼顧支出費用最小的選擇


Reference

[1] Minimum Cost For Tickets - LeetCode


回到DP特訓班目錄 和 學習路徑

52會員
339內容數
由有業界實戰經驗的演算法工程師, 手把手教你建立解題的框架, 一步步寫出高效、清晰易懂的解題答案。 著重在讓讀者啟發思考、理解演算法,熟悉常見的演算法模板。 深入淺出地介紹題目背後所使用的演算法意義,融會貫通演算法與資料結構的應用。 在幾個經典的題目融入一道題目的多種解法,或者同一招解不同的題目,擴展廣度,並加深印象。
留言0
查看全部
發表第一個留言支持創作者!
你可能也想看
用英文叫別人「別那麼急/別那麼激動」遛狗結果狗狗在路上暴走、孩子看到遊樂園等不及要衝了、朋友說話太嗨讓你快要跟不上。用三句英文讓對方或你的毛小孩「消消火」。
Thumbnail
avatar
你的英日語自學導師 譯難忘  ོꦿ༄꧁꧂
2023-12-12
用一個英文單字講人有多麼「跩」「唉呦很跩喔」、「很『秋』哦」,中文的跩和台語的秋,可以形容人很得意有自信又有點霸氣。就這麼剛好英文的own這個字可以傳達出這種fu。想知道怎麼使用嗎?這篇用超白話讓你秒懂。
Thumbnail
avatar
你的英日語自學導師 譯難忘  ོꦿ༄꧁꧂
2023-10-24
用 SEO 思維規劃以終為始的行銷策略:以 ChoozSEO 為例聊聊如何用 AI主題關鍵字工具來優化內容策略,並從中獲得更多洞見。
Thumbnail
avatar
Sho 的路上觀察手記
2023-10-18
用最簡單的日文問:「可以跟你合照嗎?」邀請日本人一起合照,卻不知道怎麼開口說出來嗎?看完這篇,馬上能現學現賣。
Thumbnail
avatar
你的英日語自學導師 譯難忘  ོꦿ༄꧁꧂
2023-10-05
用邏輯改變世界專訪(下)弱連結,真「有」用?你會察言觀色嗎?突破認知!|怪獸科技公司怪獸科技公司第二季,一起培養在快速變化社會的超強適應力!專案管理(PM)不僅涉及技術和流程的掌握,更重要的是人際溝通能力。過去曾擔任 PM 的 Davina 將帶我們深入解析 AI 時代下,她自己是養成溝通能力的一些好用方法,以及持續創新、突破認知邊界的意義。
Thumbnail
avatar
王政皓|怪獸科技公司
2023-08-30
用SPSS進行HLM第五章:步驟策略和解釋變異量測量本文章將介紹實務中進行HLM會需要注意的事項,包含樣本量要求、基本假設、計算解釋變異量和HLM建構策略。
Thumbnail
avatar
Dr. Rover
2023-08-15
劇評|《D.P:逃兵追緝令2》:走在「永恆回歸」的背後,依舊選擇戰鬥《D.P:逃兵追緝令2》雖然口碑不如第一季,但絕對不會不好看!與第一季劇情緊密相連的續作,依舊在想探討裡的主題中不停輪迴、深化、留白,留下餘韻十足的後續後,讓我們自行思考答案。雖然最後沒有給我像第一季曹石峰開槍自縊時的震撼,第二季曹石峰回歸的結尾,卻在溫暖中有了一絲「真的可以改變」甚麼的力量。
Thumbnail
avatar
夜半の故事備忘錄
2023-08-04
Netflix 原創韓劇《D.P:逃兵追緝令》,揭露韓國軍營霸凌問題的真實與震撼~D.P:逃兵追緝令 (共2季) | 評價 9/10 | awwrated https://awwrated.com/netflix/81280917 如果你對韓國的兵役制度有所了解,你可能會知道,那裡並不是一個充滿友愛和正義的地方。相反,那裡充斥著權力的濫用、暴力的威脅、心理的折磨和人性的扭曲。
Thumbnail
avatar
awwrated
2023-08-02
用SPSS進行HLM第四章:三層次之隨機截距斜率模型接續第三章內容,有時候多層次資料不只一個層次,可能具有多種層次,例如:學生屬於某個學校,而學校又屬於某個縣市。本章主要說明三層次之隨機截距模型的公式和SPSS操作,我們先從公式開始,然後在教學SPSS視窗和語法操作,相信看完後,讀者就會了解三層次之隨機截距斜率模型概念和操作。
Thumbnail
avatar
Dr. Rover
2023-07-26
用SPSS進行HLM第三章:雙層次之隨機截距斜率模型接續第二章內容,本章主要說明雙層次之隨機截距模型的公式和SPSS操作,我們先從公式開始,然後在教學SPSS視窗和語法操作,相信看完後,讀者就會了解雙層次之隨機截距斜率模型概念和操作。
Thumbnail
avatar
Dr. Rover
2023-07-13