(nice!!!)LeetCode 983. 最低票价(动态规划、递归 || 递推 || 指针)

题目: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];
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值