【Py/Java/C++三种语言OD独家2024E卷真题】20天拿下华为OD笔试之【模拟】2024E-分糖果【欧弟算法】全网注释最详细分类最全的华为OD真题题解

29 篇文章 2 订阅

可上 欧弟OJ系统 练习华子OD、大厂真题
绿色聊天软件戳 od1441了解算法冲刺训练(备注【CSDN】否则不通过)

相关推荐阅读

从2024年8月14号开始,OD机考全部配置为2024E卷
注意几个关键点:

  1. 大部分的题目仍为往期2023A+B+C以及2024D的旧题。注意万变不离其宗,把方法掌握,无论遇到什么题目都可以轻松应对。
  2. 支持多次提交题目,以最后一次提交为准。可以先做200的再做100的,然后可以反复提交。
  3. E卷仍然为单机位+屏幕监控的形式进行监考。
  4. 进入考试界面新加入了这样一段话并且用红字标出,可以看出华子对作弊代考等行为是0容忍的,请各位同学认真学习,不要妄图通过其他违规途径通过考试。
    在这里插入图片描述

在这里插入图片描述

题目描述与示例

题目描述

小明从糖果盒中随意抓一把糖果,每次小明会取出一半的糖果分给同学们。

当糖果不能平均分配时,小明可以选择从糖果盒中(假设盒中糖果足够)取出一个糖果或放回一个糖果。

小明最少需要多少次(取出、放回和平均分配均记一次),能将手中糖果分至只剩一颗。

输入描述

抓取的糖果数(<10000000000

输出描述

最少分至一颗糖果的次数

示例一

输入

15

输出

5

说明

15+1=16
16/2=8
8/2=4
4/2=2
2/2=1

示例二

输入

6

输出

3

说明

6/2=3
3-1=2
2/2=1

解题思路

本题是一道比较有意思的题目。从题意描述到解题思路,个人都比较喜欢。

本题的数据量看似给得非常大(N < 10000000000),但是仔细思考可以发现,每一次我们都会近似地让糖果数量减半,因此糖果数减少到1的速度是对数级别的。

我们可以直接使用一个O(logN)的模拟算法来解决这个问题。

考虑某一个特定的糖果数量num,且到达num的操作次数为time。当

  • num是偶数的时候,我们获得数量num // 2的糖果,需要time + 1次操作。这里的1次操作,是减半操作。
  • num是奇数的时候,我们获得数量(num+1) // 2(num-1) // 2的糖果,需要time + 2次操作。这里的2次操作,有1次是减半操作,有1次是+1-1的操作。

显然,对于任意的num,如果已知对应的time,我们就可以计算出其近似减半后的结果

而近似减半后的结果得到之后,我们又可以做类似的重复操作,直到最终糖果数量减少到1

这种重复的过程,容易想到可以使用递归来完成。考虑递归三要素:

  1. 递归入口:传入初始值的当前数量num = n,以及初始操作次数time = 0
  2. 递归子问题:num的减半过程,也就是上述的讨论。
  3. 递归终止条件:当num减少到1的时候,可以更新答案。

本题的递归过程和动态规划非常类似,可以多加以比较。

代码

python

# 题目:【模拟】2024E-分糖果
# 分值:100
# 作者:许老师-闭着眼睛学数理化
# 算法:模拟,递归
# 代码看不懂的地方,请直接在群上提问


from math import inf

# 输入初始数量n
n = int(input())
# 初始化答案变量ans为无穷大
ans = inf

# 构建递归辅助函数,num为当前糖果数,time为得到num所花费的操作次数
def help(num, time):
    # 设置ans为全局变量
    global ans
    # 如果num为1,则直接更新ans
    if num == 1:
        ans = min(ans, time)
        return
    # 否则,进行递归
    else:
        # 如果num是偶数,则获得 num // 2的操作次数为time+1
        if num % 2 == 0:
            help(num//2, time+1)
        # 如果num是奇数,则获得 (num+1)//2 和 (num-1)//2的操作次数为time+2
        else:
            help((num+1)//2, time+2)
            help((num-1)//2, time+2)

# 递归入口,传入num = n以及time = 0
help(n, 0)

# 输出答案
print(ans)

java

import java.util.Scanner;

public class Main {

    // 初始化答案变量ans为无穷大
    private static long ans = Long.MAX_VALUE;

    // 构建递归辅助函数,num为当前糖果数,time为得到num所花费的操作次数
    public static void help(long num, long time) {
        // 如果num为1,则直接更新ans
        if (num == 1) {
            ans = Math.min(ans, time);
            return;
        }
        // 否则,进行递归
        else {
            // 如果num是偶数,则获得 num // 2的操作次数为time+1
            if (num % 2 == 0) {
                help(num / 2, time + 1);
            }
            // 如果num是奇数,则获得 (num+1)//2 和 (num-1)//2的操作次数为time+2
            else {
                help((num + 1) / 2, time + 2);
                help((num - 1) / 2, time + 2);
            }
        }
    }

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

        // 输入初始数量n
        long n = scanner.nextLong();

        // 递归入口,传入num = n以及time = 0
        help(n, 0);

        // 输出答案
        System.out.println(ans);

        scanner.close();
    }
}

cpp

#include <iostream>
#include <climits>

using namespace std;

// 初始化答案变量ans为无穷大
long long ans = LLONG_MAX;

// 构建递归辅助函数,num为当前糖果数,time为得到num所花费的操作次数
void help(long long num, long long time) {
    // 如果num为1,则直接更新ans
    if (num == 1) {
        ans = min(ans, time);
        return;
    }
    // 否则,进行递归
    else {
        // 如果num是偶数,则获得 num // 2的操作次数为time+1
        if (num % 2 == 0) {
            help(num / 2, time + 1);
        }
        // 如果num是奇数,则获得 (num+1)//2 和 (num-1)//2的操作次数为time+2
        else {
            help((num + 1) / 2, time + 2);
            help((num - 1) / 2, time + 2);
        }
    }
}

int main() {
    // 输入初始数量n
    long long n;
    cin >> n;

    // 递归入口,传入num = n以及time = 0
    help(n, 0);

    // 输出答案
    cout << ans << endl;

    return 0;
}

时空复杂度

时间复杂度:O(logN)

空间复杂度:O(1)


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

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

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

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

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

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

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

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

闭着眼睛学算法

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值