632. 最小区间
难度 困难
| 标签 哈希表
双指针
字符串
Description
你有 k
个 非递减排列 的整数列表。找到一个 最小 区间,使得 k
个列表中的每个列表至少有一个数包含在其中。
我们定义如果 b-a < d-c
或者在 b-a == d-c
时 a < c
,则区间 [a,b]
比 [c,d]
小。
示例 1:
输入:nums = [[4,10,15,24,26], [0,9,12,20], [5,18,22,30]] 输出:[20,24] 解释: 列表 1:[4, 10, 15, 24, 26],24 在区间 [20,24] 中。 列表 2:[0, 9, 12, 20],20 在区间 [20,24] 中。 列表 3:[5, 18, 22, 30],22 在区间 [20,24] 中。
示例 2:
输入:nums = [[1,2,3],[1,2,3],[1,2,3]] 输出:[1,1]
示例 3:
输入:nums = [[10,10],[11,11]] 输出:[10,11]
示例 4:
输入:nums = [[10],[11]] 输出:[10,11]
示例 5:
输入:nums = [[1],[2],[3],[4],[5],[6],[7]] 输出:[1,7]
提示:
nums.length == k
1 <= k <= 3500
1 <= nums[i].length <= 50
-105 <= nums[i][j] <= 105
nums[i]
按非递减顺序排列
My Solution
typedef struct {
int val;
int setIndex;
} Set;
int Cmp(void *val1, void *val2)
{
Set *set1 = (Set*)val1;
Set *set2 = (Set*)val2;
if (set1->val < set2->val) {
return -1;
} else if (set1->val > set2->val) {
return 1;
} else {
return set1->setIndex - set2->setIndex;
}
}
void MergeArray(int **nums, Set *list, int numsSize, int *numsColSize, int totalSum)
{
int count = 0;
for (int i = 0; i < numsSize; i++) {
for (int j = 0; j < numsColSize[i]; j++) {
list[count].val = nums[i][j];
list[count].setIndex = i;
count++;
}
}
qsort(list, totalSum, sizeof(Set), Cmp);
}
bool CmpRange(int left1, int right1, int left2, int right2)
{
int distance1 = right1 - left1;
int distance2 = right2 - left2;
if (distance1 < distance2) {
return true;
} else if (distance1 > distance2) {
return false;
} else {
return left1 <= left2;
}
}
bool IsFull(int *masks, int numsSize)
{
for (int i = 0; i < numsSize; i++) {
if (masks[i] == 0) {
return false;
}
}
return true;
}
/**
* Note: The returned array must be malloced, assume caller calls free().
*/
int* smallestRange(int** nums, int numsSize, int* numsColSize, int* returnSize) {
if (numsSize == 0) {
*returnSize = 0;
return NULL;
}
int *result = (int *)malloc(sizeof(int) * 2);
*returnSize = 2;
if (numsSize == 1) {
result[0] = nums[0][0];
result[1] = nums[0][0];
return result;
}
int totalSum = 0;
for (int i = 0; i < numsSize; i++) {
totalSum += numsColSize[i];
}
Set *list = (Set *)malloc(sizeof(Set) * totalSum);
MergeArray(nums, list, numsSize, numsColSize, totalSum);
int left = 0;
int right = 0;
int minLeft = list[0].val;
int minRight = list[totalSum - 1].val;
int *masks = (int *)malloc(sizeof(int) * numsSize);
memset(masks, 0, sizeof(int) * numsSize);
int lastFull = 0;
int lastEmptyIndex = -1; //满了之后减少的那个
masks[list[0].setIndex] = 1;
bool addRight = false;
while(left <= right && right < totalSum) {
if (addRight) {
masks[list[right].setIndex]++;
}
if (lastFull) {
// printf("last is full lastEmptyIndex = %d mask = %d\n", lastEmptyIndex, masks[lastEmptyIndex]);
if (masks[lastEmptyIndex]) {
// 满的
if (CmpRange(list[left].val, list[right].val, minLeft, minRight)) {
minLeft = list[left].val;
minRight = list[right].val;
}
// printf("aa full left = %d ,right = %d, minLeft = %d ,minRight = %d \n", left, right, minLeft, minRight);
lastEmptyIndex = list[left].setIndex;
masks[lastEmptyIndex]--;
left++;
addRight = false;
} else {
right++;
addRight = true;
}
continue;
}
if (IsFull(masks, numsSize)) {
if (CmpRange(list[left].val, list[right].val, minLeft, minRight)) {
minLeft = list[left].val;
minRight = list[right].val;
}
lastFull = 1;
lastEmptyIndex = list[left].setIndex;
// printf("full left = %d ,right = %d, lastEmptyIndex = %d \n", left, right, lastEmptyIndex);
addRight = false;
masks[lastEmptyIndex]--;
left++;
} else {
right++;
addRight = true;
}
}
free(list);
result[0] = minLeft;
result[1] = minRight;
return result;
}