贪心算法训练

2021-04-10 19:50:25

跳跃游戏II

给定一个非负整数数组,你最初位于数组的第一个位置。

数组中的每个元素代表你在该位置可以跳跃的最大长度。

你的目标是使用最少的跳跃次数到达数组的最后一个位置。

输入: [2,3,1,1,4]
输出: 2
解释: 跳到最后一个位置的最小跳跃数是 2。
     从下标为 0 跳到下标为 1 的位置,跳 1 步,然后跳 3 步到达数组的最后一个位置。

假设现在在位置 k k k,那么能跳的步数 s t e p ≤ n u m s [ k ] step \leq nums[k] stepnums[k],问你从起点跳到终点最少需要多少步。

a [ i ] a[i] a[i]为跳到第 i i i位所需要的最少步数,那么 a [ i ] = m i n ( a [ i ] , a [ i − k ] + 1 ) a[i] = min(a[i], a[i-k]+1) a[i]=min(a[i],a[ik]+1) k k k为某一位跳 k k k步到 i i i

class Solution {
public:
    int jump(vector<int>& nums) {
        int n = nums.size();
        vector<int>a(n,0x3f3f3f3f);
        a[0] = 0;
        for(int i=0;i<n;++i) {
            for(int j=1;j<=nums[i];++j) {
                if(i+j <=n-1)
                    a[i+j] = min(a[i] + 1,a[i+j]);
            }
        }
        return a[n-1];
    }
};

这样写其实没有什么贪心的思想。。
如果用贪心来考虑呢?从起点开始,那就要跳到尽可能跳的远的点,比如例子 [ 2 , 3 , 1 , 1 , 4 ] [2,3,1,1,4] [2,3,1,1,4],第一个点可以跳到下标为 1 , 2 1,2 1,2的点,下标为1的最远可以跳到 4 4 4,下标为2的最远可以跳到3,所以选择跳到下标为1的。

        int n = nums.size();
        int maxPos = 0, ans = 0, e = 0;
        for(int i=0; i<n-1; ++i) {
            if(maxPos >= i) {
                maxPos = max(maxPos, i + nums[i]);
                if( i == e) {
                    e = maxPos;
                    ans ++;
                }
            }
        }
        return ans;

跳跃游戏

给定一个非负整数数组 nums ,你最初位于数组的 第一个下标 。

数组中的每个元素代表你在该位置可以跳跃的最大长度。

判断你是否能够到达最后一个下标。

这题和上题很像,不过是判断能不能到达最后一个点。
这次不需要求最小步数,所以可以维护每个点所能到达的最远点,然后判断大不大于 n − 1 n-1 n1

        int w = 0;
        for(int i=0;i<n;++i) {
            if(i > w) return false;
            w = max(w, i + nums[i]);
        }
        return true;

买卖股票的最佳时机

给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。

设计一个算法来计算你所能获取的最大利润。你可以尽可能地完成更多的交易(多次买卖一支股票)。

注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。

可以多次购买售出股票。

如果用dp来做,设 d p [ i ] [ 0 ] dp[i][0] dp[i][0]表示第 i i i时刻并且手上没有股票的最大利润,
d p [ i ] [ 1 ] dp[i][1] dp[i][1]表示第 i i i时刻并且手上有一只股票的最大利润。

可以写出状态转移方程,
d p [ i ] [ 0 ] = m a x ( d p [ i − 1 ] [ 0 ] , d p [ i − 1 ] [ 1 ] + p r i c e s [ i ] ) dp[i][0] = max(dp[i-1][0], dp[i-1][1] + prices[i]) dp[i][0]=max(dp[i1][0],dp[i1][1]+prices[i])
可以不买,或者在第i时刻卖了
d p [ i ] [ 1 ] = m a x ( d p [ i − 1 ] [ 1 ] , d p [ i − 1 ] [ 0 ] − p r i c e s [ i ] ) dp[i][1] = max(dp[i-1][1], dp[i-1][0] - prices[i]) dp[i][1]=max(dp[i1][1],dp[i1][0]prices[i])
可以在第i时刻不卖,或者在第i时刻买了

d p [ 0 ] [ 0 ] = 0 , d p [ 0 ] [ 1 ] = − p r i c e s [ 0 ] dp[0][0] = 0,dp[0][1] = -prices[0] dp[0][0]=0dp[0][1]=prices[0]

考虑贪心,只要第 i i i时刻的股票价格比第 i − 1 i-1 i1时刻高,就卖了。

class Solution {
public:
    int maxProfit(vector<int>& prices) {
        int ans = 0;
        for(int i=1;i<prices.size();++i) {
            if(prices[i] > prices[i-1]) ans+=prices[i]-prices[i-1];
        }
        return ans;
    }
};

加油站

在一条环路上有 N 个加油站,其中第 i 个加油站有汽油 gas[i] 升。

你有一辆油箱容量无限的的汽车,从第 i 个加油站开往第 i+1 个加油站需要消耗汽油 cost[i] 升。你从其中的一个加油站出发,开始时油箱为空。

如果你可以绕环路行驶一周,则返回出发时加油站的编号,否则返回 -1。

说明:

如果题目有解,该答案即为唯一答案。
输入数组均为非空数组,且长度相同。
输入数组中的元素均为非负数。

这题数据范围应该不大,暴力就能过。

class Solution {
public:
    int canCompleteCircuit(vector<int>& gas, vector<int>& cost) {
        int n = gas.size();
        vector<int>a(n,0);
        for(int i=0;i<n;++i) a[i] = gas[i] - cost[i];
        for(int i=0;i<n;++i) {
            if(a[i] >= 0) {
                int j=(i+1)%n,g=a[i];
                bool ok = true;
                while(j!=i) {
                    g += a[j];
                    j = (j+1)%n;
                    if(g<0) {
                        ok = false;
                        break;
                    }
                }
                if(ok) return i;
            }
        }
        return -1;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值