- 最近做的leetcode有点多,没时间更新博客,后面多做一些基础算法题;
- 今天上午周赛做了一道DP题目,不过当时没有想到使用DP,囧
题目
给定一个数组days,表示今年的旅行计划,你可以买单日票,周票和月票
- 求:旅行的最低花费
- 如下特点:1 <= days.length <= 365;1 <= days[i] <= 365,元素特点是单调递增的。
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.
分析
- 这题不用DP,也暂时没想到其他时间复杂度较低的解法;
- DP思路比较简单,但是根据题目特点有O(n)和O(365)两种解法
解法1:
public int mincostTickets(int[] days, int[] costs) {
// dp[i + 1] .. days[0, .., i]的最优解
// dp[i] = min(dp[week] + costs[1], dp[month] + costs[2], dp[i - 1] + costs[0]);
int week = 0;
int month = 0;
int[] dp = new int[days.length + 1];
dp[0] = 0;
for (int i = 0; i < days.length; i++) {
while(days[week] < days[i] - 6) {
week++;
}
while(days[month] < days[i] - 29) {
month++;
}
int tmp = Math.min(dp[i] + costs[0], dp[week] + costs[1]);
dp[i + 1] = Math.min(tmp, dp[month] + costs[2]);
}
return dp[days.length];
}
解法2:
public int mincostTickets(int[] days, int[] costs) {
boolean[] dayIncluded = new boolean[366];
for (int day : days) {
dayIncluded[day] = true;
}
int[] minCost = new int[366];
minCost[0] = 0;
for (int day = 1; day <= 365; ++day) {
if (!dayIncluded[day]) {
minCost[day] = minCost[day-1];
continue;
}
int min;
min = minCost[day-1] + costs[0];
min =Math.min(min, minCost[Math.max(0, day-7)] + costs[1]);
min = Math.min(min, minCost[Math.max(0, day-30)] + costs[2]);
minCost[day] = min;
}
return minCost[365];
}