剑指offer_抽象建模能力

剑指 Offer 60. n个骰子的点数

题目

在这里插入图片描述

代码

方法一:迭代解法

class Solution {
public:
    vector<double> dicesProbability(int n) {
        //动态规划
        int min = n, max = n * 6;
        double dp[n + 1][max + 1];
        //结果数组的个数有n*5-1个
        vector<double> res(n * 5 + 1);
        //base case 
        for(int j = 1; j <= 6; j++) {
            dp[1][j] = 1 / 6.0;
        }
        //状态转移
        for(int i = 2; i <= n;i++) {
            for(int j = i; j <= i * 6 ;j++) {
                for(int k = 1; k <= 6; k++) {
                    if(j - k > 0) {
                        //通过i-1个骰子扔出点数j-k
                        dp[i][j] = dp[i][j] + dp[i - 1][j - k]/6;
                    }else {
                        break;
                    }
                }
            }
        }
        for(int i = 0;i <= 5*n;i++){
            res[i] = dp[n][n+i];
        }
        return res;
    }
};

方法二:递归解法

class Solution {
public:
    vector<double> dicesProbability(int n) {
        //初始化1个骰子的概率数组
        vector<double> dp(6, 1.0 / 6.0);
        for(int i = 2; i <= n; i++) {
            //新数组存放骰子的每个总数和出现的概率
            //骰子总数为i时,骰子可能出现的点数i~6i,长度6i-i+1
            vector<double> temp(5 * i + 1, 0);
            //遍历骰子数为i-1的概率数组,计算骰子数为i时点数的概率
            for(int j = 0; j < dp.size(); j++) {
                for(int k = 0; k < 6; k++) {
                    temp[j + k] = temp[j + k] + dp[j] / 6.0;
                }
            }
            骰子总数为i的数组赋值骰子总数为i-1的数组
            dp = temp;
        }
        return dp;
    }
};

剑指 Offer 61. 扑克牌中的顺子

题目

在这里插入图片描述

代码

首先要理解第二个数据用例的意思是大小王可以替代任何牌。
再遍历数组,找出数组的最大值和最小值,除开大小王即0之外,数组中不能有相等的数字,如果有则返回false,如果最大值和最小值相差超过5也返回false。

class Solution {
public:
    bool isStraight(vector<int>& nums) {
        //注意大小王能替代任意牌
        int max = 0, min = 14;
        set<int>rep;
        for(int i = 0; i < 5; i++) {
            if(nums[i] == 0) {
                continue;
            }
            max = max > nums[i] ? max : nums[i];
            min = min < nums[i] ? min : nums[i];
            if(rep.find(nums[i]) != rep.end()) {
                return false;
            }
            rep.insert(nums[i]);

        }
        return max - min < 5;
    }
};

剑指 Offer 62. 圆圈中最后剩下的数字

题目

在这里插入图片描述

本来以为该题和“CCF201712-2 游戏”这个题目时一样的原理,但仔细看是不一样的。该题是每次淘汰之后,重新从0开始记数到m个数淘汰它,而后者报数一直增加,遇到k的倍数或者个位数为k则淘汰。

代码

本题是著名的 “约瑟夫环” 问题,可使用 动态规划 解决。
长度为 n 的序列会先删除第 m % n 个元素,然后剩下一个长度为 n - 1 的序列。那么,我们可以求解 f(n - 1, m)

class Solution {
public:
    int lastRemaining(int n, int m) {
        int x = 0;
        for (int i = 2; i <= n; i++) {
            x = (x + m) % i;
        }
        return x;
    }
};

剑指 Offer 63. 股票的最大利润

题目

在这里插入图片描述

代码

法一:
双层for循环遍历

class Solution {
public:
    int maxProfit(vector<int>& prices) {
        //动态规划
        int n = prices.size();
        int maxvalue = 0;
        int sell = 0;
        //外层找买入
        for(int i = 0; i < n; i++){
            //内层找卖出
            sell = prices[i];
            for(int j = i + 1; j < n; j++) {
               sell = max(sell, prices[j]);
            }
             maxvalue = max(maxvalue, sell - prices[i]);
        }
        return maxvalue;
        
    }
};

法二:
动态规划(未压缩)

class Solution {
public:
    int maxProfit(vector<int>& prices) {
        int n = prices.size();
        if(n == 0) {
            return 0;
        }
        //dp[i][j],i表示天数,j表示当前持有状态,0表示未持有,1表示持有
        vector<vector<int>>dp(n, vector<int>(2));
        //base case
        dp[0][0] = 0;
        dp[0][1] = -prices[0];
        //状态转移
        for(int i = 1; i < n; i++) {
            dp[i][0] = max(dp[i - 1][0], dp[i - 1][1] + prices[i]);
            dp[i][1] = max(-prices[i], dp[i - 1][1]);
        }
        return dp[n - 1][0];
    }
};

法三:
压缩后的动态规划

class Solution {
public:
    int maxProfit(vector<int>& prices) {
        int n = prices.size();
        if(n == 0) {
            return 0;
        }
        //base case
        int dp_i_0 = 0, dp_i_1 = -prices[0];
        //状态转移
        for(int i = 1; i < n; i++) {
            // dp[i][0] = max(dp[i-1][0], dp[i-1][1] + prices[i])
            dp_i_0 = max(dp_i_0, dp_i_1 + prices[i]);
            // dp[i][1] = max(dp[i-1][1], -prices[i])
            dp_i_1 = max(-prices[i], dp_i_1);
        }
        return dp_i_0;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值