ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

LeetCode/最低加油次数

2022-07-03 03:00:22  阅读:264  来源: 互联网

标签:stations int 次数 加油站 startFuel 加油 LeetCode dp


汽车从起点出发驶向目的地,该目的地位于出发位置东面 target 英里处。
沿途有加油站,每个 station[i] 代表一个加油站,它位于出发位置东面 station[i][0] 英里处,并且有 station[i][1] 升汽油。
假设汽车油箱的容量是无限的,其中最初有 startFuel 升燃料。它每行驶 1 英里就会用掉 1 升汽油。
当汽车到达加油站时,它可能停下来加油,将所有汽油从加油站转移到汽车中。
为了到达目的地,汽车所必要的最低加油次数是多少?如果无法到达目的地,则返回 -1

1. 贪心算法

类似青蛙跳跃,更新维护最远加油站,不足以到达下一加油站时选取已经过加油站的最大油量

class Solution {
public:
    int minRefuelStops(int target, int startFuel, vector<vector<int>>& stations) {
        priority_queue<int> q;
        stations.push_back({target, 0});//终点当做加油站
        int last = 0, ans = 0;
        for (int i = 0; i < stations.size(); ++i) {
            auto need = stations[i][0] - last;//需要的油量
            while (!q.empty() && startFuel < need) {
                startFuel += q.top(); q.pop(); //取已走过加油站最大油量
                ans++;//计数增加
            }
            if (startFuel >= need) {//油量满足需求
                startFuel -= need;//到达下一加油站
                q.push(stations[i][1]);//把油量加入优先队列
            } 
            else return -1;
            last = stations[i][0];//更新上一位置
        }
        return ans;//遍历结束说明能到达最后加油站,即终点
    }
};

2. 动态规划(哈希表)

记录到达i加油站时的状态,即对应加油次数和所剩油量
后面的状态只需从前一个状态转移记录,当存在相同加油次数的路径时,取较大剩余油量
最后记录所有能达到最终目标的次数,更新取最小值
这里存在很多剪枝的细节,以及把起点和终点当加油站的处理方式,方便统一操作,减少判断

class Solution {
public:
    int minRefuelStops(int target, int startFuel, vector<vector<int>>& stations) {
        stations.push_back({target,0});//把终点当做加油站,统一处理
        int n = stations.size();
        vector<map<int,long>> dp(n+1);//表示到达i车站时对应加油次数和所剩油量,这里利用哈希表的自动排序
        dp[0][0] = startFuel;
        int prepos = 0;//记录上一个加油站的位置
        int mincount = INT_MAX;
        for(int i=1;i<=n;i++){//遍历得到所有加油站状态
            //if(dp[i-1].size()==0) return -1;//不能到达前一个加油站,返回-1
            for (auto& it : dp[i - 1]) {//从上一个加油站所有状态开始判断,从小到大
            if(it.first>=mincount) break;//剪枝
            if (it.second >= target - prepos) { mincount = min(it.first, mincount);break; }//剪枝
            //如果能到达下一个加油站
            int remain = it.second - (stations[i - 1][0] - prepos);//剩余油量
            if (remain >= 0) {
                //相同次数时,保留剩余油量多的
                if(remain>dp[i][it.first])
                    dp[i][it.first] = remain;//不加油
                if((long)remain + stations[i - 1][1]> dp[i][it.first + 1])
                    dp[i][it.first + 1] = (long)remain + stations[i - 1][1];//加油
            }
        }
        prepos = stations[i - 1][0];//记录上一次加油站位置
    }
    if(mincount!=INT_MAX) return mincount;
    return -1;
    }
};

3. 动态规划(一维)

动态维护加油i次时的最远距离,新增加油站时,对所有值从后往前进行更新
dp[i]表示加油i次能到达的最远距离
这里其实也是经过二维动态规划压缩后的结果

class Solution {
public:
    int minRefuelStops(int target, int startFuel, vector<vector<int>>& stations) {
        vector<unsigned int> dp(stations.size() + 1);//dp[i]表示加油i次能到达的最远距离
        dp[0] = startFuel;
        //从前往后遍历考察每个加油站
        for(int i = 0; i < stations.size(); i++)
            //新增加油站后,从后往前更新dp表,从后往前才不会对下一个造成影响
            for(int j = i; j >= 0; j--)
                if(dp[j] >= stations[i][0])//如果加油j次能到达i加油站
                    dp[j + 1] = max(dp[j + 1], dp[j] + stations[i][1]);//更新j+1次的最远距离

        for(int i = 0; i < dp.size(); i++)
            if(dp[i] >= target) return i;//返回一个最小加油次数
        return -1;
    }
};

标签:stations,int,次数,加油站,startFuel,加油,LeetCode,dp
来源: https://www.cnblogs.com/929code/p/16439134.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有