做护士题的那个网站是什么/互联网哪个行业前景好
#我回归了家人们,我将持续更新,并保证高质量内容#
题目取自LeetCode每日一题2502,大家可自行练习或者验证自己思路
题目
给你一个整数
n
,表示下标从 0 开始的内存数组的大小。所有内存单元开始都是空闲的。请你设计一个具备以下功能的内存分配器:
- 分配 一块大小为
size
的连续空闲内存单元并赋 idmID
。- 释放 给定 id
mID
对应的所有内存单元。注意:
- 多个块可以被分配到同一个
mID
。- 你必须释放
mID
对应的所有内存单元,即便这些内存单元被分配在不同的块中。实现
Allocator
类:
Allocator(int n)
使用一个大小为n
的内存数组初始化Allocator
对象。int allocate(int size, int mID)
找出大小为size
个连续空闲内存单元且位于 最左侧 的块,分配并赋 idmID
。返回块的第一个下标。如果不存在这样的块,返回-1
。int freeMemory(int mID)
释放 idmID
对应的所有内存单元。返回释放的内存单元数目。示例:
输入 ["Allocator", "allocate", "allocate", "allocate", "freeMemory", "allocate", "allocate", "allocate", "freeMemory", "allocate", "freeMemory"] [[10], [1, 1], [1, 2], [1, 3], [2], [3, 4], [1, 1], [1, 1], [1], [10, 2], [7]] 输出 [null, 0, 1, 2, 1, 3, 1, 6, 3, -1, 0]
代码基础框架
class Allocator {
public:
Allocator(int n) {
}
int allocate(int size, int mID) {
}
int freeMemory(int mID) {
}
};
/**
* Your Allocator object will be instantiated and called as such:
* Allocator* obj = new Allocator(n);
* int param_1 = obj->allocate(size,mID);
* int param_2 = obj->freeMemory(mID);
*/
题目分析
目标:设计一个内存分配器,支持分配和释放操作。分配时需要找到最左侧的连续空闲块,释放时需清除所有指定ID的内存单元。
关键要求:
我们需要设计一个内存分配器,支持以下功能:
-
分配:找到最左侧的连续
size
个空闲内存单元,分配给mID
,并返回起始下标。 -
释放:释放所有
mID
对应的内存单元,返回释放的数量。
解题思路
1. 问题分析
-
内存表示:用一个数组
arr
表示内存单元,arr[i]
的值表示第i
个内存单元的状态。-
arr[i] == 0
:空闲。 -
arr[i] > 0
:已分配给某个mID
。
-
-
分配逻辑:
-
需要找到最左侧的连续
size
个空闲单元。 -
如果找到,将其分配给
mID
,并返回起始下标;否则返回-1
。
-
-
释放逻辑:
-
遍历数组,将所有
mID
对应的单元置为0
,并统计释放的数量。
-
2. 破题关键
-
如何找到最左侧的连续空闲块:
-
遍历数组,统计连续空闲单元的数量。
-
当连续空闲单元数量达到
size
时,记录起始位置并分配。
-
-
如何高效释放内存:
-
遍历数组,将所有
mID
对应的单元置为0
,并统计数量。
-
代码逐行解析
1. 初始化
class Allocator {int[] arr;public Allocator(int n) {arr = new int[n]; // 初始化大小为 n 的内存数组,所有单元初始为 0(空闲)} }
-
作用:初始化一个大小为
n
的内存数组,所有单元初始为0
,表示空闲。
2. 分配方法 allocate
public int allocate(int size, int mID) {int cnt = 0; // 计数器,记录当前连续空闲单元的数量for (int i = 0; i < arr.length; i++) {if (arr[i] > 0) { // 当前单元已被分配cnt = 0; // 重置计数器continue;}cnt++; // 当前单元空闲,增加计数器if (cnt == size) { // 找到足够的连续空闲单元Arrays.fill(arr, i - size + 1, i + 1, mID); // 分配内存return i - size + 1; // 返回起始下标}}return -1; // 没有找到足够的连续空闲单元 }
-
逻辑:
-
初始化计数器
cnt
,用于记录当前连续空闲单元的数量。 -
遍历数组
arr
:-
如果当前单元已被分配(
arr[i] > 0
),重置计数器cnt = 0
。 -
如果当前单元空闲(
arr[i] == 0
),增加计数器cnt++
。 -
当
cnt == size
时,表示找到足够的连续空闲单元:-
使用
Arrays.fill
将这段内存单元赋值为mID
。 -
返回这段内存块的起始下标
i - size + 1
。
-
-
-
如果遍历完数组仍未找到足够的连续空闲单元,返回
-1
。
-
-
示例:
-
假设
arr = [0, 0, 0, 0, 0]
,调用allocate(2, 1)
:-
找到最左侧的连续 2 个空闲单元,分配为
[1, 1, 0, 0, 0]
,返回0
。
-
-
3. 释放方法 freeMemory
public int freeMemory(int mID) {int size = 0; // 计数器,记录释放的内存单元数量for (int i = 0; i < arr.length; i++) {if (arr[i] == mID) { // 当前单元属于 mIDarr[i] = 0; // 释放内存单元size++; // 增加计数器}}return size; // 返回释放的内存单元数量 }
-
逻辑:
-
初始化计数器
size
,用于记录释放的内存单元数量。 -
遍历数组
arr
:-
如果当前单元属于
mID
(arr[i] == mID
),将其释放(设为0
),并增加计数器size++
。
-
-
返回
size
,表示释放的内存单元数量。
-
-
示例:
-
假设
arr = [1, 1, 0, 2, 2]
,调用freeMemory(1)
:-
释放所有
mID = 1
的单元,变为[0, 0, 0, 2, 2]
,返回2
。
-
-
复杂度分析
-
分配方法
allocate
:-
时间复杂度:
O(n)
,最坏情况下需要遍历整个数组。 -
空间复杂度:
O(1)
,只使用了常数空间。
-
-
释放方法
freeMemory
:-
时间复杂度:
O(n)
,需要遍历整个数组。 -
空间复杂度:
O(1)
,只使用了常数空间。
-
-
核心思想:通过数组模拟内存单元,遍历处理分配和释放。
-
优点:实现简单,逻辑清晰。
-
缺点:在大规模数据下,时间复杂度较高。
-
优化方向:可以使用更高效的数据结构(如链表或线段树)来管理空闲块,减少时间复杂度。
代码
class Allocator {int[] arr;public Allocator(int n) {arr = new int[n];}public int allocate(int size, int mID) {int cnt = 0;for(int i = 0; i < arr.length; i++){if(arr[i] > 0){cnt = 0;continue;}cnt++;if(cnt == size){Arrays.fill(arr, i - size + 1, i + 1, mID);return i - size + 1;}}return -1;}public int freeMemory(int mID) {int size = 0;for(int i = 0; i < arr.length; i++){if(arr[i] == mID){arr[i] = 0;size++;}}return size;}
}/*** Your Allocator object will be instantiated and called as such:* Allocator obj = new Allocator(n);* int param_1 = obj.allocate(size,mID);* int param_2 = obj.freeMemory(mID);*/
其余思路代码分享
一、Runtime:28ms
class Allocator {private int n;private int[] memory;public Allocator(int n) {this.n = n;this.memory = new int[n];}public int allocate(int size, int mID) {int count = 0;for (int i = 0; i < n; ++i) {if (memory[i] != 0) {count = 0;} else {++count;if (count == size) {for (int j = i - count + 1; j <= i; ++j) {memory[j] = mID;}return i - count + 1;}}}return -1;}public int freeMemory(int mID) {int count = 0;for (int i = 0; i < n; ++i) {if (memory[i] == mID) {++count;memory[i] = 0;}}return count;}
}
二、Runtime:8ms
class Allocator {int[] arr; // 存放数据, arr[i]到arr[i + len[i] - 1]范围内都是arr[i]数据int[] len; // 存放数据长度, len[i]不等于0才有效, 表示arr[i]数据的长度public Allocator(int n) {this.arr = new int[n]; // 初始化默认都是0this.len = new int[n];this.len[0] = n; // 初始mem[0]数据的长度就是n}public int allocate(int size, int mID) {for (int i = 0; i < arr.length; i += len[i]) {if (arr[i] == 0 && len[i] >= size) {// 如果当前数据是0且范围足够if (i + size < arr.length && arr[i + size] == 0) {// 超过size范围之后还是0,说明当前范围超过size,// 也可以直接用len[i] > size判断,更新0的长度len[i + size] = len[i] - size;}arr[i] = mID;len[i] = size;return i;}}return -1;}public int freeMemory(int mID) {int res = 0;// 先删掉数据for (int i = 0; i < arr.length; i += len[i]) {if (arr[i] == mID) {res += len[i];arr[i] = 0;}}// 删掉后为0的范围和其相邻的本来就是0的范围合并for (int i = 0; i < arr.length; i += len[i]) {if (arr[i] == 0) {int j = i + len[i];while (j < arr.length && arr[j] == 0) {j += len[j];}len[i] = j - i;}}return res;}
}/*** Your Allocator object will be instantiated and called as such:* Allocator obj = new Allocator(n);* int param_1 = obj.allocate(size,mID);* int param_2 = obj.freeMemory(mID);*/
制作不易,感谢你的查阅、关注、评论和点赞