华为OD机试真题---内存资源分配

华为OD机试中的“内存资源分配”题目是一道经典的资源分配类题目,它考察考生如何有效地管理和分配有限的资源,并能根据用户的请求优先分配合适的资源。以下是对该题目的详细解析:

一、题目描述

有一个简易内存池,内存按照大小粒度分类,每个粒度有若干个可用内存资源。用户会进行一系列内存申请,系统需要按需分配内存池中的资源,并返回每次申请是否成功的结果。

二、分配规则

  1. 分配的内存要大于等于内存的申请量。
  2. 存在满足需求的内存就必须分配。
  3. 优先分配粒度小的内存块,但不能拆分内存块使用,只能分配整块。
  4. 按申请顺序分配内存,先申请的优先处理。
  5. 有可用内存分配则申请结果为true,没有可用则返回false。

三、输入描述

输入为两行字符串:

  • 第一行为内存池资源列表,包含内存粒度数据信息,粒度数据间用逗号分割。一个粒度信息内用冒号分割,冒号前为内存粒度大小,冒号后为数量。资源列表不大于1024,每个粒度的数量不大于4096。
  • 第二行为申请列表,申请的内存大小间用逗号分割。申请列表不大于100000。

四、输出描述

输出为一行字符串,表示每次内存申请的结果(成功为true,失败为false),结果间用逗号分割。

五、示例

输入:

64:2,128:1,32:4,1:128
50,36,64,128,127

输出:

true,true,true,false,false

六、解题思路

  1. 解析输入数据,将内存池资源列表和申请列表分别转换为适当的数据结构(如列表或字典)。
  2. 遍历申请列表,对于每个申请,按顺序检查内存池中的资源:
    • 从粒度最小的资源开始检查,看是否有足够的内存满足申请。
    • 如果有,则分配内存,并更新内存池的状态(减少该粒度的可用数量)。
    • 如果没有,则继续检查下一个粒度的资源。
    • 如果所有粒度的资源都不满足申请,则记录申请失败。
  3. 输出每次申请的结果。

七、代码实现

在Java中,你可以通过创建一个类来模拟内存资源分配的过程。以下是一个简单的实现,它遵循了华为OD机试中“内存资源分配”题目的要求:

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;

public class MemoryAllocator {
    // 内存池,使用TreeMap来保持粒度有序(从小到大)
    private final TreeMap<Integer, Integer> memoryPool;

    // 构造函数,初始化内存池
    public MemoryAllocator(String poolStr) {
        memoryPool = new TreeMap<>();
        String[] poolEntries = poolStr.split(",");
        for (String entry : poolEntries) {
            String[] parts = entry.split(":");
            int size = Integer.parseInt(parts[0]);
            int count = Integer.parseInt(parts[1]);
            memoryPool.put(size, count);
        }
    }

    /**
     * 分配内存并返回结果
     *
     * 本方法旨在处理多个内存分配请求,并将处理结果以布尔值的形式存储在列表中返回
     * 每个请求以逗号分隔,并且每个请求的大小将被解析为整数
     *
     * @param requestStr 包含多个内存分配请求的字符串,每个请求的大小以逗号分隔
     * @return 包含每个内存分配请求结果的列表,true表示成功分配,false表示分配失败
     */
    public List<Boolean> allocateMemory(String requestStr) {
        List<Boolean> results = new ArrayList<>();
        // 将输入字符串分割成多个内存分配请求
        String[] requests = requestStr.split(",");
        // 遍历每个请求,尝试分配内存,并记录结果
        for (String request : requests) {
            int requestSize = Integer.parseInt(request);
            boolean allocated = allocate(requestSize);
            results.add(allocated);
        }
        return results;
    }

    // 尝试分配指定大小的内存
    /**
     * 本函数旨在从内存池中分配指定大小的内存块。
     * 它会遍历内存池,寻找第一个大于或等于所需大小的可用内存块,并减少其可用数量。
     * 如果找到合适的内存块并成功分配,则返回true;否则,返回false。
     *
     * @param size 需要分配的内存大小
     * @return 如果成功分配内存,则返回true;否则返回false。
     */
    private boolean allocate(int size) {
        // 遍历内存池,从最小的粒度开始尝试
        for (Map.Entry<Integer, Integer> entry : memoryPool.entrySet()) {
            int granularity = entry.getKey();
            int available = entry.getValue();
            // 检查当前粒度是否满足大小要求且有可用的内存块
            if (granularity >= size && available > 0) {
                // 分配内存并更新内存池状态
                memoryPool.put(granularity, available - 1);
                // 成功分配内存,返回true
                return true;
            }
        }
        // 没有找到合适的内存块,返回false
        return false;
    }

    // 主函数,用于测试
    public static void main(String[] args) {
        String poolStr = "64:2,128:1,32:4,1:128";
        String requestStr = "50,36,64,128,127";
        MemoryAllocator allocator = new MemoryAllocator(poolStr);
        List<Boolean> results = allocator.allocateMemory(requestStr);
        // 输出结果
        System.out.println(String.join(",", results.stream().map(String::valueOf).toArray(String[]::new)));
    }
}

八、代码解释

  1. 内存池表示

    • 使用TreeMap<Integer, Integer>来存储内存池,其中键是内存粒度(大小),值是该粒度下可用内存块的数量。TreeMap保证了键的自然排序,这样我们可以从最小的粒度开始尝试分配内存。
  2. 构造函数

    • MemoryAllocator(String poolStr):解析输入的内存池字符串,并将其转换为TreeMap中的条目。
  3. 内存分配

    • allocateMemory(String requestStr):解析输入的请求字符串,并逐个处理每个请求。对于每个请求,调用allocate(int size)方法尝试分配内存,并将结果添加到结果列表中。
    • allocate(int size):遍历内存池,从最小的粒度开始,查找第一个能够满足请求的内存块。如果找到,则分配该内存块(将对应粒度的可用数量减1),并返回true。如果遍历完所有粒度都没有找到合适的内存块,则返回false
  4. 测试

    • main函数中,我们创建了一个MemoryAllocator对象,并使用示例输入进行测试。最后,将结果列表转换为逗号分隔的字符串并输出。

九、运行示例解析

初始化内存池

首先,我们创建一个MemoryAllocator实例,并传入一个字符串poolStr来描述内存池。在这个字符串中,每个内存块的大小和数量由冒号分隔,不同的内存块由逗号分隔。

例如,对于输入字符串:

String poolStr = "64:2,128:1,32:4,1:128";

内存池将被初始化为:

  • 64大小的内存块有2个。
  • 128大小的内存块有1个。
  • 32大小的内存块有4个。
  • 1大小的内存块有128个。

这些内存块按照大小存储在TreeMap中,确保它们按照从小到大的顺序排列。

分配内存

接下来,我们调用allocateMemory方法来处理一系列内存分配请求。每个请求的大小由逗号分隔。

例如,对于输入字符串:

String requestStr = "50,36,64,128,127";

我们尝试分配以下大小的内存:

  1. 50
  2. 36
  3. 64
  4. 128
  5. 127
内存分配过程
  1. 分配50大小的内存

    • 检查内存池,找到第一个大于或等于50的内存块是64。
    • 64大小的内存块有2个,可以分配一个。
    • 更新内存池:64大小的内存块剩余1个。
    • 分配成功。
  2. 分配36大小的内存

    • 再次检查内存池,找到第一个大于或等于36的内存块是64。
    • 64大小的内存块有1个(之前已经分配了一个),可以分配一个。
    • 注意:虽然32大小的内存块更接近36,但因为我们从最小的满足条件的粒度开始分配(这是当前实现的一个限制),所以我们选择64。
    • 更新内存池:64大小的内存块为0,无法再分配。
    • 分配成功。
  3. 分配64大小的内存

    • 检查内存池,发现没有64大小的内存块了。
    • 下一个更大的内存块是128,但它太大,不满足“最小满足条件”的当前策略(实际上,这里可以改进策略以更好地利用内存)。
    • 分配失败。
  4. 分配128大小的内存

    • 检查内存池,找到128大小的内存块,有1个。
    • 分配一个128大小的内存块。
    • 更新内存池:128大小的内存块剩余0个。
    • 分配成功。
  5. 分配127大小的内存

    • 检查内存池,发现没有127大小的内存块,且所有现有的内存块都不满足这个大小(128太大)。
    • 分配失败。
结果

最后,allocateMemory方法返回一个布尔列表,表示每个内存分配请求的结果:

[true, true, false, true, false]
输出

main函数中,我们将这个结果列表转换为逗号分隔的字符串并打印出来:

System.out.println(String.join(",", results.stream().map(String::valueOf).toArray(String[]::new)));

输出结果为:

true,true,false,true,false

十、改进建议

当前的内存分配策略是简单的“最小满足条件”策略,即找到第一个大于或等于请求大小的内存块进行分配。这种策略在某些情况下可能不是最优的(例如,当存在多个接近请求大小的内存块时)。可以通过更复杂的策略(如最佳拟合、首次拟合等)来改进内存分配的效率。

十一、注意事项

  1. 内存不能拆分使用,只能分配整块。
  2. 按申请顺序分配内存,先申请的优先处理。
  3. 输出结果要与输入申请的顺序一一对应。
### 华为OD真实题目与编程练习资料 华为OD的题目通常分为多个版本,例如A卷、B卷、C卷等[^2]。这些卷可能包含一些历史题目的重复以及新增加的内容。对于准备此类考的人来说,了解历年真题及其解法是非常重要的。 #### 历年真题分析 在2023年的华为OD中,有一道关于Java实现分糖果的经典算法问题被广泛讨论,并提供了详细的解题思路和代码示例[^1]。这表明该类题不仅考察基本语法掌握情况,还注重逻辑思维能力的应用。 以下是基于上述提到的一道典型例题——“分糖果”的解决方案: ```java import java.util.*; public class CandyDistribution { public static void main(String[] args) { Scanner scanner = new Scanner(System.in); int n = scanner.nextInt(); // 孩子数量 int m = scanner.nextInt(); // 糖果总数 List<Integer> distributionList = distributeCandies(n, m); System.out.println(distributionList.toString()); } private static List<Integer> distributeCandies(int childrenCount, int candyTotal){ List<Integer> result = new ArrayList<>(childrenCount); for (int i=0;i<childrenCount;i++) { result.add(0); } while(candyTotal > 0){ for(int j=0; j<result.size() && candyTotal >0 ;j++){ result.set(j,result.get(j)+1); candyTotal--; } } return result; } } ``` 此程序实现了公平分配一定量的糖果给若干名儿童的过程。通过循环遍历列表来逐一增加每位孩子的糖果数直到没有剩余为止。 #### 获取更多资源的方法 为了更好地备战华为OD,可以参考牛客网上的专项训练模块以及其他公开渠道分享的相关经验贴。特别是针对不同类型的算法设计模式行深入学习,比如动态规划、贪心策略等高级技巧。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值