【Py/Java/C++三种语言OD独家2024D卷真题】20天拿下华为OD笔试之【DP】2024D-抢7游戏【欧弟算法】全网注释最详细分类最全的华为OD真题题解

有LeetCode算法/华为OD考试扣扣交流群可加 948025485
可上全网独家的 欧弟OJ系统 练习华子OD、大厂真题
绿色聊天软件戳 od1441了解算法冲刺训练(备注【CSDN】否则不通过)

从2024年4月15号开始,OD机考全部配置为2024D卷
注意两个关键点:

  1. 会遇到C卷复用题。虽然可能存在幸存者偏差,但肯定还会有一大部分的旧题。
  2. 现在又支持做完题目之后倒回去改了。就是可以先做200的再做100的,然后可以反复提交。
    在这里插入图片描述

题目描述与示例

题目描述

AB两个人玩抢7游戏,游戏规则为A先报一个起始数字X (10 <= X <= 10000),B报下一个数字Y,(0<X-Y<3),A再报一个数字Z(0<Y-Z<3),以此类推,直到其中一个抢到7,抢到7即为胜者,在B赢得比赛的情况下,一共有多少种组合?

输入描述

起始数字M,如100

10 <= M <= 10000

输出描述

B能赢得比赛的组合次数

示例

输入

10

输出

1

说明

只有一种赢的组合,A起始选择10B接着选择9A接着选择8B接着选择7赢得胜利。

解题思路

正确DP解法

AB每次选择的数字,只能比上一个数字小12,两个人所选择的数字越来越小直到降为7。这种计算组合数的问题很容易想到使用动态规划来解题。

我们考虑动态规划三部曲:

  1. dp数组的含义是什么?

由于AB两个人是交替地进行数字选择的,我们可以构建两个dp数组,dpAdpB

dpA[i]表示A选择了第i个数字时的方法数,dpB[i]表示B选择了第i个数字时的方法数。

  1. 动态转移方程是什么?

由于两个人的选择是交替进行的,因此A的状态由先前的B转移得到,B的状态由先前的A转移得到。

B选择了数字i时,上一轮A的选择必然是i+1i+2。因此B选择数字i的组合数为A选择了数字i+1i+2的组合数的总和,即存在动态转移方程dpB[i] = dpA[i+1] + dpA[i+2]

对于A选择了数字i的情况,同理存在dpA[i] = dpB[i+1] + dpB[i+2]

由于选择是从大到小进行的,因此必须从M-1开始进行逆序遍历,直到选择了7。即

for i in range(M-1, 6, -1):
    dpB[i] = dpA[i+1] + dpA[i+2]
    dpA[i] = dpB[i+1] + dpB[i+2]

print(dpB[7])

最终dpB[7]就是B抢到了7赢得最终胜利的方法数。

  1. dp数组如何初始化?

由于dp过程是从M-1开始的,当i = M-1时,需要使用到i+2 = M+1这个值,因此可以初始化dpAdpB数组均为长度为M+2的一维数组(或哈希表也可以,因为小于7的那些位置实际上是没有用到的)。

由于A最开始报的数字是M,换句话说A取得数字M的方法数只有1种,因此初始化dpA[M] = 1,其余位置均初始化为0。即

dpA = [0] * (M+2)
dpB = [0] * (M+2)
dpA[M] = 1

上述过程用到了两个dp数组,看起来似乎比较冗长。

实际上可以把两个动态转移方程进行合并,只得到一个关于dpB的动态转移方程。将

dpA[i+1] = dpB[i+2] + dpB[i+3]dpA[i+2] = dpB[i+3] + dpB[i+4]代入dpB[i] = dpA[i+1] + dpA[i+2],可以得到新的动态转移方程dpB[i] = dpB[i+2] + 2*dpB[i+3] + dpB[i+4],这样就只需要一个dpB数组和一个动态转移方程即可。

整体的代码修改为

M = int(input())

dpB = [0] * (M+2)
dpB[M-1] = 1
dpB[M-2] = 1

for i in range(M-3, 6, -1):
    dpB[i] = dpB[i+2] + 2*dpB[i+3] + dpB[i+4]

print(dpB[7])

错误题目

但是,本题考试时所用的用例存在很大的问题,应该是一道错题。争议很大。(出题人真的很傻逼)

这个DP方法虽然是正确的(确信),但是因为题目用例本身给的有问题,所以通过率很低。

有同学测出了以下用例:

输入 = 11 输出 = 3
输入 = 12 输出 = 6
输入 = 13 输出 = 16
输入 = 15 输出 = 120

这几个用例可以直接写死,用if语句进行输出。

其余输入则仍然沿用原DP方法,这样最终能得到66.7%的通过率。

代码

Python

# 题目:【DP】2023C-抢7游戏
# 分值:200
# 作者:许老师-闭着眼睛学数理化
# 算法:DP
# 代码看不懂的地方,请直接在群上提问


# 输入A的初始报数
M = int(input())

# 初始化dpA和dpB两个初始数组
dpA = [0] * (M+2)
dpB = [0] * (M+2)
dpA[M] = 1

# dp过程,从M-1开始遍历,到7结束
for i in range(M-1, 6, -1):
    dpB[i] = dpA[i+1] + dpA[i+2]
    dpA[i] = dpB[i+1] + dpB[i+2]

# 输出dpB[7]即为最终答案
print(dpB[7])

Java

import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);

        // 输入A的初始报数
        long M = scanner.nextLong();

        // 初始化dpA和dpB两个初始数组
        long[] dpA = new long[(int) (M + 2)];
        long[] dpB = new long[(int) (M + 2)];
        dpA[(int) M] = 1;

        // dp过程,从M-1开始遍历,到7结束
        for (int i = (int) (M - 1); i >= 7; i--) {
            dpB[i] = dpA[i + 1] + dpA[i + 2];
            dpA[i] = dpB[i + 1] + dpB[i + 2];
        }

        // 输出dpB[7]即为最终答案
        System.out.println(dpB[7]);
    }
}

C++

#include <iostream>
using namespace std;

int main() {
    // 输入A的初始报数
    long long M;
    cin >> M;

    // 初始化dpA和dpB两个初始数组
    long long dpA[M + 2] = {0};
    long long dpB[M + 2] = {0};
    dpA[M] = 1;

    // dp过程,从M-1开始遍历,到7结束
    for (int i = M - 1; i >= 7; i--) {
        dpB[i] = dpA[i + 1] + dpA[i + 2];
        dpA[i] = dpB[i + 1] + dpB[i + 2];
    }

    // 输出dpB[7]即为最终答案
    cout << dpB[7] << endl;

    return 0;
}

时空复杂度

时间复杂度:O(N)

空间复杂度:O(N)


华为OD算法/大厂面试高频题算法练习冲刺训练

  • 华为OD算法/大厂面试高频题算法冲刺训练目前开始常态化报名!目前已服务300+同学成功上岸!

  • 课程讲师为全网50w+粉丝编程博主@吴师兄学算法 以及小红书头部编程博主@闭着眼睛学数理化

  • 每期人数维持在20人内,保证能够最大限度地满足到每一个同学的需求,达到和1v1同样的学习效果!

  • 60+天陪伴式学习,40+直播课时,300+动画图解视频,300+LeetCode经典题,200+华为OD真题/大厂真题,还有简历修改、模拟面试、专属HR对接将为你解锁

  • 可上全网独家的欧弟OJ系统练习华子OD、大厂真题

  • 可查看链接 大厂真题汇总 & OD真题汇总(持续更新)

  • 绿色聊天软件戳 od1336了解更多

  • 25
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值