#P3092. 内存资源分配(100分)
-
1000ms
Tried: 141
Accepted: 37
Difficulty: 4
所属公司 :
华为od
-
算法标签>二分算法
内存资源分配(100分)
题面描述:
题目要求实现一个简易的内存池管理器。输入包含两行,第一行为内存池资源列表,格式为“粒度大小:数量”,不同粒度用逗号分隔;第二行为用户的内存申请列表,申请的内存大小用逗号分隔。程序需要按照先后顺序处理内存申请,优先分配粒度最小且大于等于申请量的内存,若有可用内存则分配,成功则返回true,否则返回false。输出为一个布尔列表,表示每次申请是否成功。
思路
将所有资源按照大小和数量存起来并按照大小升序排列,对于每一个申请优先找第一个大于等于它的资源可以做到最优,二分查找即可
题解分析
-
输入处理:
- 读取内存资源和内存申请的列表。每个资源的大小和数量通过逗号分隔的字符串输入,存入二维向量(
vector<vector<int>>)中,其中每个元素保存了资源的大小和对应的数量。
- 读取内存资源和内存申请的列表。每个资源的大小和数量通过逗号分隔的字符串输入,存入二维向量(
-
内存资源排序:
- 为了能够高效地找到最适合的内存粒度,首先将内存资源按照粒度的大小进行升序排序。
-
二分查找:
- 在处理每个内存申请时,通过二分查找来快速找到第一个大于等于申请量的内存粒度。二分查找的复杂度为O(logn),使得查找效率很高。
-
分配和更新资源:
- 如果找到符合条件的内存粒度,就进行分配,并将对应的数量减一。如果某个粒度的内存数量为零,就从资源列表中删除该粒度。
- 如果没有找到合适的内存粒度,返回
false表示分配失败。
-
输出结果:
- 每次分配结果以
true或false的形式输出,按照题目要求,用逗号分隔各个申请的结果。 - 整体时间复杂度为O(mlogn),其中m为申请次数,n为内存粒度数量。
- 每次分配结果以
c++
#include <bits/stdc++.h>
using namespace std;
// 比较函数,用于对内存资源按照大小升序排列
bool cmp(vector<int> a, vector<int> b) {
return a[0] < b[0];
}
// 二分查找,寻找第一个大于等于申请量res的内存粒度
int get(vector<vector<int>> temp, int res) {
int l = 0, r = temp.size() - 1;
while (l <= r) {
int mid = l + r >> 1;
int ans = temp[mid][0]; // 当前的内存粒度大小
if (ans > res) {
r = mid - 1; // 如果粒度大于申请量,向左找
} else if (ans < res) {
l = mid + 1; // 如果粒度小于申请量,向右找
} else {
return mid; // 找到正好等于申请量的粒度,返回其索引
}
}
return l; // 返回第一个大于等于申请量的粒度
}
signed main() {
// 处理输入的内存资源信息,使用二维向量存储每个粒度及其数量
int size, cnt;
char c;
vector<vector<int>> v; // 存储每个内存粒度及其数量
while (cin >> size) {
getchar(); // 跳过冒号
cin >> cnt; // 读取数量
v.emplace_back(vector<int>{size, cnt}); // 存入每个资源的大小和数量
if (getchar() != ',') break; // 如果没有逗号,说明输入结束
}
// 处理输入的内存申请列表
vector<int> num; // 存储每个申请的内存大小
while (cin >> size) {
num.push_back(size); // 记录申请大小
if (getchar() != ',') break; // 如果没有逗号,说明输入结束
}
// 将内存资源按照大小升序排列
sort(v.begin(), v.end(), cmp);
// 遍历每个申请,进行内存分配
for (int i = 0; i < num.size(); i++) {
// 使用二分查找寻找第一个大于等于申请量的内存粒度
int j = get(v, num[i]);
if (j < v.size()) { // 如果找到合适的内存粒度
cout << "true";
if (--v[j][1] == 0) { // 分配后减少数量,如果数量为0,删除该粒度
v.erase(v.begin() + j);
}
} else { // 如果没有找到合适的内存粒度
cout << "false";
}
if (i < num.size() - 1) cout << ","; // 输出格式:用逗号分隔
}
}
python
# 二分查找,寻找第一个大于等于申请量res的内存粒度
def get(temp, res):
l, r = 0, len(temp) - 1
while l <= r:
mid = (l + r) // 2
ans = temp[mid][0] # 当前的内存粒度大小
if ans > res:
r = mid - 1 # 如果粒度大于申请量,向左找
elif ans < res:
l = mid + 1 # 如果粒度小于申请量,向右找
else:
return mid # 找到正好等于申请量的粒度,返回其索引
return l # 返回第一个大于等于申请量的粒度
# 比较函数,用于对内存资源按照大小升序排列
def cmp(a):
return a[0]
def main():
# 处理输入的内存资源信息
v = []
resources = input().split(",") # 先按逗号分隔内存资源
for resource in resources:
size, cnt = map(int, resource.split(":")) # 分别读取粒度大小和数量
v.append([size, cnt])
# 处理输入的内存申请列表
num = list(map(int, input().split(","))) # 存储每个申请的内存大小
# 将内存资源按照大小升序排列
v.sort(key=cmp)
# 遍历每个申请,进行内存分配
result = []
for i in range(len(num)):
# 使用二分查找寻找第一个大于等于申请量的内存粒度
j = get(v, num[i])
if j < len(v): # 如果找到合适的内存粒度
result.append("true")
v[j][1] -= 1 # 分配后减少数量
if v[j][1] == 0: # 如果数量为0,删除该粒度
v.pop(j)
else: # 如果没有找到合适的内存粒度
result.append("false")
# 输出结果,使用逗号分隔
print(",".join(result))
# 调用主函数
if __name__ == "__main__":
main()
java
import java.util.*;
public class Main { // 改为Main类
// 二分查找,寻找第一个大于等于申请量res的内存粒度
public static int get(List<int[]> temp, int res) {
int l = 0, r = temp.size() - 1;
while (l <= r) {
int mid = (l + r) / 2;
int ans = temp.get(mid)[0]; // 当前的内存粒度大小
if (ans > res) {
r = mid - 1; // 如果粒度大于申请量,向左找
} else if (ans < res) {
l = mid + 1; // 如果粒度小于申请量,向右找
} else {
return mid; // 找到正好等于申请量的粒度,返回其索引
}
}
return l; // 返回第一个大于等于申请量的粒度
}
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
// 处理输入的内存资源信息
List<int[]> v = new ArrayList<>();
String[] resources = scanner.nextLine().split(","); // 先按逗号分隔内存资源
for (String resource : resources) {
String[] parts = resource.split(":");
int size = Integer.parseInt(parts[0]);
int cnt = Integer.parseInt(parts[1]);
v.add(new int[]{size, cnt});
}
// 处理输入的内存申请列表
String[] numStr = scanner.nextLine().split(",");
int[] num = new int[numStr.length];
for (int i = 0; i < numStr.length; i++) {
num[i] = Integer.parseInt(numStr[i]);
}
// 将内存资源按照大小升序排列
Collections.sort(v, Comparator.comparingInt(a -> a[0]));
// 遍历每个申请,进行内存分配
List<String> result = new ArrayList<>();
for (int i = 0; i < num.length; i++) {
// 使用二分查找寻找第一个大于等于申请量的内存粒度
int j = get(v, num[i]);
if (j < v.size()) { // 如果找到合适的内存粒度
result.add("true");
v.get(j)[1]--; // 分配后减少数量
if (v.get(j)[1] == 0) { // 如果数量为0,删除该粒度
v.remove(j);
}
} else { // 如果没有找到合适的内存粒度
result.add("false");
}
}
// 输出结果,使用逗号分隔
System.out.println(String.join(",", result));
scanner.close();
}
}
题目描述
有一个简易内存池,内存按照大小粒度分类,每个粒度有若干个可用内存资源,用户会进行一系列内存申请,需要按需分配内存池中的资源返回申请结果成功失败列表。
分配规则如下:
- 分配的内存要大于等于内存的申请量,存在满足需求的内存就必须分配,优先分配粒度小的,但内存不能拆分使用;
- 需要按申请顺序分配,先申请的先分配。
- 有可用内存分配则申请结果为true,没有可用则返回false。
注意:不考虑内存释放
输入描述
输入为两行字符串
第一行为内存池资源列表,包含内存粒度数据信息,粒度数据间用逗号分割
- 一个粒度信息内用冒号分割,冒号前为内存粒度大小,冒号后为数量
- 资源列表不大于1024
- 每个粒度的数量不大于4096
第二行为申请列表,申请的内存大小间用逗号分割
- 申请列表不大于100000
如 64:2,128:1,32:4,1:12850,36,64,128,127
输出描述
输出为内存池分配结果
如true,true,true,false,false
样例1
输入
64:2,128:1,32:4,1:128
50,36,64,128,127
输出
true,true,true,false,false
说明
内存池资源包含:64K共2个、128K共1个、32K共4个、1K共128个的内存资源;
针对50,36,64,128,127的内存申请序列,分配的内存依次是:64,64,128,NULL,NULL,
第三次申请内存时已经将128分配出去,因此输出结果是:
true,true,true,false,false