acwing-16

acwing-16

骰子的点数(简单)

将一个骰子投掷n次,获得的总点数为s,s的可能范围为n~6n。

掷出某一点数,可能有多种掷法,例如投掷2次,掷出3点,共有[1,2],[2,1]两种掷法。

请求出投掷n次,掷出n~6n点分别有多少种掷法。

样例1
输入:n=1

输出:[1, 1, 1, 1, 1, 1]

解释:投掷1次,可能出现的点数为1-6,共计6种。每种点数都只有1种掷法。所以输出[1, 1, 1, 1, 1, 1]。
样例2
输入:n=2

输出:[1, 2, 3, 4, 5, 6, 5, 4, 3, 2, 1]

解释:投掷2次,可能出现的点数为2-12,共计11种。每种点数可能掷法数目分别为1,2,3,4,5,6,5,4,3,2,1。

      所以输出[1, 2, 3, 4, 5, 6, 5, 4, 3, 2, 1]。
  • 采用动态规划思路
  • 设置二维数组dp[i][j]表示i个骰子投掷出点数为j的投掷方法
  • 递推式dp[i][j]=dp[i-1][j-1]+dp[i-1][j-2]+dp[i-1][j-3]+dp[i-1][j-4]dp[i-1][j-5]+dp[i-1][j-6]
  • 结果为dp[n][n]--dp[n][6n]
class Solution {
public:
    vector<int> numberOfDice(int n) {
        //dp[i][j]表示i个骰子投掷出点数为j的投掷方法
        vector<vector<int>> dp(n+1,vector<int>(6*n+1));
        dp[0][0]=1;
        for(int i=1;i<=n;i++){
            for(int j=1;j<=6*i;j++){
                for(int k=1;k<=min(j,6);k++)
                dp[i][j]+=dp[i-1][j-k];
            }
        }
        vector<int> res;
        for(int i=n;i<=6*n;i++)res.push_back(dp[n][i]);
        return res;
    }
};

扑克牌的顺子(简单)

从扑克牌中随机抽5张牌,判断是不是一个顺子,即这5张牌是不是连续的。

2~10为数字本身,A为1,J为11,Q为12,K为13,大小王可以看做任意数字。

为了方便,大小王均以0来表示,并且假设这副牌中大小王均有两张。

样例1
输入:[8,9,10,11,12]

输出:true
样例2
输入:[0,8,9,11,12]

输出:true
  • 特判数组是否为空
  • 先将数组中零跳出计算
  • 判断是否有对子
  • 数组中除零之外最大值最小值的差是否为小于4(因为只有五张牌)
class Solution {
public:
    bool isContinuous( vector<int> numbers ) {
        
        if(numbers.size()==0)return false;
        sort(numbers.begin(),numbers.end());
        int k=0;
        while(numbers[k]==0)k++;
        
        for(int i=k+1;i<numbers.size();i++)
        if(numbers[i-1]==numbers[i])return false;
        
        return numbers.back()-numbers[k]<=4;
    }
};

圆圈中最后剩下的数字(简单)

0, 1, …, n-1这n个数字(n>0)排成一个圆圈,从数字0开始每次从这个圆圈里删除第m个数字。

求出这个圆圈里剩下的最后一个数字。

样例
输入:n=5 , m=3

输出:3
  • 数组模拟
  • 将数组的元素值记为下一个元素值的下标
  • 每次将游标游动m-1位,将元素的下标值修改为-1
  • 这样到最后,所有元素值要么是-1要么是元素下标本身,而元素下标本身即为答案
class Solution {
public:
    int lastRemaining(int n, int m){
        vector<int> ans;
        
        for(int i=0;i<n;i++)
        ans.push_back((i+1)%n);
        
        int pos,f=0;
        while(ans[f]!=f){
            for(int i=0;i<m-1;i++){pos=f;f=ans[f];}
            ans[pos]=ans[f];ans[f]=-1;f=ans[pos];
        }
        return ans[f];
    }
};
  • 约瑟夫递推

  • 设置递推表达式f(n,m)表示n个人围成圈,从这个圆圈中删除第m个数字所得到的人的编号

  • 递推关系

    • 假设我们在这个圆圈中删除第m-1号人(n从零号开始)

    • 那么我们将从第m号人开始从新从0开始编号

    • 那么我们可以得到原始编号和新的编号的映射关系应该是

      旧编号=(新编号+m)%n

    • 而删除一个人之后表达式就变成了f(n-1.m)

    • 从而可以得到递推关系是f(n,m)=(f(n-1,m)+m)%n

class Solution {
public:
    int lastRemaining(int n, int m){
        if(n==1)return 0;
        return (lastRemaining(n-1,m)+m)%n;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值