执行结果:通过
执行用时和内存消耗如下:
代码如下:
#define maxn 100005
int heap[maxn];
int heap_count;
int **rec, *nx;
bool heap_comp(int *first, int *second) {
return rec[*first][nx[*first]] < rec[*second][nx[*second]];
}
void swap(int *first, int *second) {
int temp = *second;
*second = *first;
*first = temp;
return;
}
void push(int num) {
int pos = ++heap_count;
heap[pos] = num;
while (pos > 1) {
if (heap_comp(&heap[pos], &heap[pos >> 1])) {
swap(&heap[pos], &heap[pos >> 1]);
pos >>= 1;
} else
break;
}
return;
}
void pop() {
int top_num = 1;
int now;
swap(&heap[top_num], &heap[heap_count--]);
while ((now = (top_num << 1)) <= heap_count) {
if (heap_comp(&heap[now + 1], &heap[now]) && now < heap_count) now++;
if (heap_comp(&heap[now], &heap[top_num])) {
swap(&heap[top_num], &heap[now]);
top_num = now;
} else
break;
}
}
int top() { return heap[1]; }
int *smallestRange(int **nums, int numsSize, int *numsColSize,
int *returnSize) {
heap_count = 0;
nx = (int *)malloc(sizeof(int) * numsSize);
memset(nx, 0, sizeof(int) * numsSize);
rec = nums;
int rangeLeft = 0, rangeRight = 2147483647;
int minValue = 0, maxValue = -2147483648;
for (int i = 0; i < numsSize; ++i) {
push(i);
maxValue = fmax(maxValue, nums[i][0]);
}
while (true) {
int row = top();
pop();
minValue = nums[row][nx[row]];
if (maxValue - minValue < rangeRight - rangeLeft) {
rangeLeft = minValue;
rangeRight = maxValue;
}
if (nx[row] == numsColSize[row] - 1) {
break;
}
++nx[row];
maxValue = fmax(maxValue, nums[row][nx[row]]);
push(row);
}
int *ret = malloc(sizeof(int) * 2);
ret[0] = rangeLeft, ret[1] = rangeRight;
*returnSize = 2;
return ret;
}
解题思路:
这段代码实现了一个寻找多个数组中任意取一个元素所能构成的最小范围(即最大值与最小值之差最小)的功能。下面是这段代码的打卡思路,包括其数据结构、主要函数的作用和整体流程:
数据结构
- 最大堆(通过数组实现):
heap[maxn]
:用于存储堆的元素,这里的元素是数组的索引。heap_count
:当前堆中元素的数量。
- 辅助变量:
rec
:一个指向二维数组首元素的指针,用于访问原始数组。nx
:一个整数数组,用于记录每个数组当前取到哪个元素(即列索引)。
主要函数
- heap_comp:
- 比较两个堆元素(数组索引)对应的当前值,返回较小值的索引应该排在前面的布尔值。
- swap:
- 交换两个整数的值。
- push:
- 将一个新元素加入堆中,并维护堆的性质(最大堆)。
- pop:
- 从堆中移除并返回堆顶元素(最大值),并维护堆的性质。
- top:
- 返回堆顶元素(最大值),但不移除它。
- smallestRange:
- 核心函数,用于找到多个数组中任意取一个元素所能构成的最小范围。
整体流程
- 初始化:
- 初始化堆为空。
- 分配并初始化
nx
数组,用于记录每个数组当前取到哪个元素。 - 将所有数组的第一个元素(索引为0的元素)加入堆中,并更新当前的最大值
maxValue
。
- 寻找最小范围:
- 不断从堆中取出当前最大值所在的数组索引
row
,并更新当前的最小值minValue
。 - 如果当前的最大值与最小值之差比之前记录的最小范围还小,则更新最小范围。
- 检查是否已遍历完当前数组的所有元素,如果是,则停止循环。
- 否则,移动到数组的下一个元素,更新
nx[row]
,并将该元素的新值(如果比当前maxValue
大)与maxValue
比较,更新maxValue
。 - 将新的数组索引(即下一个要比较的元素所在数组的索引)加入堆中。
- 不断从堆中取出当前最大值所在的数组索引
- 返回结果:
- 分配并初始化一个长度为2的整数数组
ret
,用于存储最小范围的最小值和最大值。 - 返回
ret
数组和returnSize
(设置为2)。
- 分配并初始化一个长度为2的整数数组
注意事项
- 这段代码使用了最大堆来确保每次取出的都是当前所有数组中的最大值。
- 通过维护每个数组当前取到哪个元素的信息(
nx
数组),可以高效地更新最小值和最大值。 - 代码中的
while (true)
循环确保了所有可能的元素组合都被考虑,直到无法再找到更小的范围为止。