Dynamic Programming学习笔记 (47) - 最低票价 (力扣# 983)

149 阅读2分钟

本题出自力扣题库第983题。题面大意如下:

有三种不同价格的火车票,一天有效的售价为 costs[0];七天有效的售价为 costs[1];三十天有效的售价为 costs[2。 如果我们在第2天买了一张7天有效的车票,那么我们可以连着旅行7天:第2、第3、第4、第5、第6、第7和第8天。 数组days给出需要旅行的日子,每一项是一个从1到365的整数。 返回完成在days中列出的每一天的旅行所需要的最低消费。

示例:

输入: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,完成days种的每一天的旅行。

题解:

本题的基本思路在于给定一个1到365之间的整数k,如果k不在days列表中,那么我们不用花钱就可递归到k+1,当k在days列表中,我们有三个选择:1)花费costs[0]然后递归到k+1;2)花费costs[1]然后递归到k+7;3)花费costs[2]然后递归到k+30,三者之间的最小值就是对k而言的答案。

Java代码如下:

import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;

class Solution {
    int[] costs;
    Set<Integer> dayset;
    int lastDay;

    int[] dp;

    public int mincostTickets(int[] days, int[] costs) {
        this.costs = costs;
        this.lastDay = days[days.length - 1];

        dp = new int[366];

        dayset = new HashSet();
        for (int day: days) {
            dayset.add(day);
        }

        return helper(1);
    }

    public int helper(int i) {
        if (i > lastDay) {
            return 0;
        }

        if (dp[i] > 0) {
            return dp[i];
        }

        int result;
        if (dayset.contains(i)) {
            int optionA = costs[0] + helper(i + 1);
            int optionB = costs[1] + helper(i + 7);
            int optionC = costs[2] + helper(i + 30);

            result = Math.min(optionA, Math.min(optionB, optionC));
        } else {
            result = helper(i+1);
        }
        return dp[i] = result;
    }
}