【CODE】最低票價

983. 最低票價

難度中等104收藏分享切換爲英文關注反饋

在一個火車旅行很受歡迎的國度,你提前一年計劃了一些火車旅行。在接下來的一年裏,你要旅行的日子將以一個名爲 days 的數組給出。每一項是一個從 1 到 365 的整數。

火車票有三種不同的銷售方式:

  • 一張爲期一天的通行證售價爲 costs[0] 美元;
  • 一張爲期七天的通行證售價爲 costs[1] 美元;
  • 一張爲期三十天的通行證售價爲 costs[2] 美元。

通行證允許數天無限制的旅行。 例如,如果我們在第 2 天獲得一張爲期 7 天的通行證,那麼我們可以連着旅行 7 天:第 2 天、第 3 天、第 4 天、第 5 天、第 6 天、第 7 天和第 8 天。

返回你想要完成在給定的列表 days 中列出的每一天的旅行所需要的最低消費。

示例 1:

輸入:days = [1,4,6,7,8,20], costs = [2,7,15]
輸出:11
解釋: 
例如,這裏有一種購買通行證的方法,可以讓你完成你的旅行計劃:
在第 1 天,你花了 costs[0] = $2 買了一張爲期 1 天的通行證,它將在第 1 天生效。
在第 3 天,你花了 costs[1] = $7 買了一張爲期 7 天的通行證,它將在第 3, 4, ..., 9 天生效。
在第 20 天,你花了 costs[0] = $2 買了一張爲期 1 天的通行證,它將在第 20 天生效。
你總共花了 $11,並完成了你計劃的每一天旅行。

示例 2:

輸入:days = [1,2,3,4,5,6,7,8,9,10,30,31], costs = [2,7,15]
輸出:17
解釋:
例如,這裏有一種購買通行證的方法,可以讓你完成你的旅行計劃: 
在第 1 天,你花了 costs[2] = $15 買了一張爲期 30 天的通行證,它將在第 1, 2, ..., 30 天生效。
在第 31 天,你花了 costs[0] = $2 買了一張爲期 1 天的通行證,它將在第 31 天生效。 
你總共花了 $17,並完成了你計劃的每一天旅行。

提示:

  1. 1 <= days.length <= 365
  2. 1 <= days[i] <= 365
  3. days 按順序嚴格遞增
  4. costs.length == 3
  5. 1 <= costs[i] <= 1000
class Solution {
public:
    /*時間複雜度:O(W),其中 W = 365 是旅行計劃中日期的最大值,我們需要計算 W 個解,而每個解最多需要查詢 3 個其他的解,因此計算量爲 O(3 * W)==O(W)。
    空間複雜度:O(W),我們需要長度爲 O(W) 的數組來存儲所有的解。
    執行用時 :60 ms, 在所有 C++ 提交中擊敗了5.20%的用戶
    內存消耗 :104.8 MB, 在所有 C++ 提交中擊敗了20.00%的用戶*/
    int helper(vector<int> d,int i,vector<int> &dp,vector<int> costs){
        if(i>365) return 0;
        if(dp[i]!=-1) return dp[i];
        if(d[i]==0) dp[i]=helper(d,i+1,dp,costs);
        else{
            dp[i]=min(min(helper(d,i+1,dp,costs)+costs[0],helper(d,i+7,dp,costs)+costs[1]),helper(d,i+30,dp,costs)+costs[2]);
        }
        return dp[i];
    }
    int mincostTickets(vector<int>& days, vector<int>& costs) {
        /*動態規劃:dp[i]表示從第i天到最後一天
        如果第i天不在days裏面,那麼dp[i]=dp[i+1]
        如果第i天在days裏面,那麼dp[i]=min(cost[0]+dp[i+1],cost[1]+dp[i+7],cost[2]+dp[i+30])*/
        vector<int> d(366);
        vector<int> dp(366,-1);
        for(auto a:days) d[a]=1;
        return helper(d,1,dp,costs);
    }
};
class Solution {
public:
    /*時間複雜度:O(N),其中 N 是出行日期的數量,我們需要計算 N 個解,而計算每個解的過程中最多將指針挪動 30 步,計算量爲 O(30 * N)=O(N)。
    空間複雜度:O(N),我們需要長度爲 O(N) 的數組來存儲所有的解。
    執行用時 :20 ms, 在所有 C++ 提交中擊敗了6.36%的用戶
    內存消耗 :22.7 MB, 在所有 C++ 提交中擊敗了20.00%的用戶*/
    int durations[3] = {1, 7, 30};
    int helper(int i,vector<int> &dp,vector<int> costs,vector<int> days){
        if(i>=days.size()) return 0;
        if(dp[i]!=-1) return dp[i];
        dp[i]=INT_MAX;
        int j=i;
        for(int k=0;k<3;k++){
            while(j<days.size() && days[j]<days[i]+durations[k]) j++;
            dp[i]=min(dp[i],helper(j,dp,costs,days)+costs[k]);
        }
        return dp[i];
    }
    int mincostTickets(vector<int>& days, vector<int>& costs) {
        /*動態規劃:dp[i]表示從第days[i]天到最後一天的最小花費
        因爲如果第k天不在days裏面,那麼這一天花費的計算一直要往後找,直到找到一天在days裏面
        dp[i]=min(dp[j1]+cost[0],dp[j7]+cost[1],dp[j30]+cost[2])
        其中j1是滿足days[j1]>=days[i]+1的最小下標,days[j7]>=days[i]+7,days[j30]>=days[i]+30*/
        vector<int> dp(days.size(),-1);
        return helper(0,dp,costs,days);
    }
};

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章