题目:983. 最低票价
方法一:递归,记忆化的dfs。时间复杂度0(365)
class Solution {
public:
//记忆化数组,sta[i]表示在1~i天花费的最低消费
vector<int> sta;
//集合,用于存储数组days中实际旅游的日子
unordered_set<int> st;
//参数u:第u天
int dfs(int u,vector<int>& costs){
//表示已近遍历结束
if(u<=0) return 0;
//表明之前已经遍历过
if(sta[u]!=-1) return sta[u];
//表示当天不在days里
if(!st.count(u)) return dfs(u-1,costs);
//找到最低消费
return sta[u]=min(dfs(u-1,costs)+costs[0],min(dfs(u-7,costs)+costs[1],dfs(u-30,costs)+costs[2]));
}
int mincostTickets(vector<int>& days, vector<int>& costs) {
//初始化为-1
sta=vector<int>(days.back()+1,-1);
//集合
st=unordered_set<int>(days.begin(),days.end());
//递归dfs
return dfs(days.back(),costs);
}
};
JAVA版本:
class Solution {
int dfs(int u,int[] costs,int[] sta,boolean[] st){
if(u<=0) return 0;
if(sta[u]>0) return sta[u];
if(!st[u]) return dfs(u-1,costs,sta,st);
return sta[u]=Math.min(dfs(u-1,costs,sta,st)+costs[0],
Math.min(dfs(u-7,costs,sta,st)+costs[1],dfs(u-30,costs,sta,st)+costs[2]));
}
public int mincostTickets(int[] days, int[] costs) {
int n=days.length;
int[] sta=new int[days[n-1]+1];
boolean[] st=new boolean[days[n-1]+1];
for(var x:days){
st[x]=true;
}
return dfs(days[n-1],costs,sta,st);
}
}
方法二:递推,动态规划。时间复杂度0(365)
class Solution {
public:
int mincostTickets(vector<int>& days, vector<int>& costs) {
//f[i]表示在1~i天花费的最低消费
vector<int> f(days.back()+1,0);
//集合,用于存储数组days中实际旅游的日子
unordered_set<int> st(days.begin(),days.end());
//动态规划,从最低天数1开始枚举
for(int i=1;i<=days.back();i++){
//旅游日子不包含该天
if(!st.count(i)) f[i]=f[i-1];
else{
//找到最低消费
f[i]=min(f[i-1]+costs[0],min(f[max(i-7,0)]+costs[1],f[max(i-30,0)]+costs[2]));
}
}
return f[days.back()];
}
};
方法三:动态规划+指针优化。如果days里的元素很大,那么上面两种方法均会超时。使用指针优化,让时间复杂度只与数组days的大小有关。
class Solution {
public:
int mincostTickets(vector<int>& days, vector<int>& costs) {
int n=days.size();
//状态f[i]表示:数组days区间[0,i-1]]满足的最低消费
vector<int> f(n+1,0);
//指针j记录最远的7天内的下标,指针k记录最远的30天内的下标,
int j=0,k=0;
for(int i=0;i<n;i++){
//确保在满足距离为7、30天内的距离最远的下标
while(days[j]<=days[i]-7) j++;
while(days[k]<=days[i]-30) k++;
//那么选最优值的话,就可以用j、k前面的下标j-1、k-1来进行状态装换。
//避免下标越界,都进行+1处理。
f[i+1]=min(f[i]+costs[0],min(f[j]+costs[1],f[k]+costs[2]));
}
return f[n];
}
};
JAVA 版本:
class Solution {
public int mincostTickets(int[] days, int[] costs) {
int n=days.length;
int[] f=new int[n+1];
int j=0,k=0;
for(int i=0;i<n;i++){
while(days[j]<=days[i]-7) j++;
while(days[k]<=days[i]-30) k++;
f[i+1]=Math.min(f[i]+costs[0],Math.min(f[j]+costs[1],f[k]+costs[2]));
}
return f[n];
}
}