描述
给定一个非空且只包含非负数的整数数组 nums
,数组的 度 的定义是指数组里任一元素出现频数的最大值。
你的任务是在 nums
中找到与 nums
拥有相同大小的度的最短连续子数组,返回其长度。
示例 1:
输入:nums = [1,2,2,3,1] 输出:2 解释: 输入数组的度是 2 ,因为元素 1 和 2 的出现频数最大,均为 2 。 连续子数组里面拥有相同度的有如下所示: [1, 2, 2, 3, 1], [1, 2, 2, 3], [2, 2, 3, 1], [1, 2, 2], [2, 2, 3], [2, 2] 最短连续子数组 [2, 2] 的长度为 2 ,所以返回 2 。
示例 2:
输入:nums = [1,2,2,3,1,4,2] 输出:6 解释: 数组的度是 3 ,因为元素 2 重复出现 3 次。 所以 [2,2,3,1,4,2] 是最短子数组,因此返回 6 。
提示:
nums.length
在1
到50,000
范围内。nums[i]
是一个在0
到49,999
范围内的整数。
答案1
//哈希表然后val值最大的就是数组的度,输出度最大的位置差+1;若有多个一样大的度,输出位置差+1最小的那个值
struct HashTable {
int key;
int num, add1, add2;
UT_hash_handle hh;
}; //定义哈希表,num为出现的次数,add1为第一次出现的位置,add2为第二次出现的位置
int findShortestSubArray(int* nums, int numsSize) {
struct HashTable* hanshTable = NULL;
for (int i = 0; i < numsSize; i++) {
struct HashTable* tmp;
HASH_FIND_INT(hanshTable, &nums[i], tmp);//在哈希表中查询是否已经存储过该数组元素值
if (tmp == NULL) {//第一次出现该值则将出现次数num初始化为1第一次出现位置和最后一次出现位置设置为当前数组下标
tmp = malloc(sizeof(struct HashTable));
tmp->key = nums[i], tmp->num = 1, tmp->add1 = i, tmp->add2 = i;
HASH_ADD_INT(hanshTable, key, tmp);
} else {//num+1并且记录最后出现的位置为当前数组下标
tmp->num++, tmp->add2 = i;
}
}
int maxNum = 0, minLen = 0;//maxNum记录数组的度,minLen记录最短连续子数组的长度
struct HashTable *s, *tmp;
HASH_ITER(hh, hanshTable, s, tmp) {//遍历哈希表
if (maxNum < s->num) {//找出数组最大的度
maxNum = s->num;
minLen = s->add2 - s->add1 + 1;
} else if (maxNum == s->num) {//若当前已为最大度则更新最短连续子数组。
if (minLen > s->add2 - s->add1 + 1) {
minLen = s->add2 - s->add1 + 1;
}
}
}
return minLen;
}
详解1
-
定义了一个结构体
HashTable
用来表示哈希表中的每个元素,包括了键值key
、出现次数num
,以及第一次出现的位置add1
和最后一次出现的位置add2
。 -
在
findShortestSubArray
函数中,首先创建了一个指向HashTable
结构体的指针hanshTable
,用于存储哈希表。 -
然后,遍历输入数组
nums
,对于数组中的每个元素,如果哈希表中已经存在该元素,则更新其出现次数num
和最后一次出现位置add2
;否则,在哈希表中添加该元素,并初始化其出现次数为1,第一次和最后一次出现位置为当前遍历的位置。 -
接下来,遍历完数组后,得到了哈希表中每个元素的出现次数以及第一次和最后一次出现的位置。
-
然后,使用变量
maxNum
来记录数组的度,即出现次数的最大值;使用变量minLen
来记录最短连续子数组的长度,初始化为0。 -
再次遍历哈希表,对于每个元素,如果其出现次数等于数组的度
maxNum
,则更新最短连续子数组的长度minLen
,取当前元素的最后一次出现位置减去第一次出现位置再加1的最小值。 -
最后,返回变量
minLen
,即为最短连续子数组的长度。哈希表(散列表)看这一篇就够了!-CSDN博客
答案2
int findShortestSubArray(int* nums, int numsSize) {
// 统计每个元素出现的次数、第一次出现的位置和最后一次出现的位置
int count[50000] = {0}; // 数组的值在 0 到 49,999 范围内
int firstIndex[50000] = {0};
int lastIndex[50000] = {0};
// 遍历数组,统计信息
int maxCount = 0;
for (int i = 0; i < numsSize; ++i) {
int num = nums[i];
if (count[num] == 0) { // 第一次出现
firstIndex[num] = i;
}
lastIndex[num] = i; // 更新最后一次出现的位置
count[num]++; // 更新出现次数
maxCount = count[num] > maxCount ? count[num] : maxCount; // 更新最大出现次数
}
// 找出满足度的最短连续子数组的长度
int minLength = INT_MAX;
for (int i = 0; i < numsSize; ++i) {
int num = nums[i];
if (count[num] == maxCount) {
int length = lastIndex[num] - firstIndex[num] + 1;
minLength = length < minLength ? length : minLength; // 更新最短长度
}
}
return minLength;
}
详解2
-
findShortestSubArray
函数的定义:- 参数
nums
是一个指向整数数组的指针,表示输入的非空且只包含非负数的整数数组。 - 参数
numsSize
表示数组nums
的长度。
- 参数
-
在函数内部,定义了三个数组
count
、firstIndex
和lastIndex
来分别记录每个元素的出现次数、第一次出现的位置和最后一次出现的位置。这三个数组的索引对应数组nums
中的元素值。 -
使用一个循环遍历数组
nums
,统计每个元素的出现次数、第一次出现的位置和最后一次出现的位置。具体步骤如下:- 对于数组中的每个元素
num
,如果它是第一次出现,则记录其第一次出现的位置i
到数组firstIndex
中。 - 每次更新元素
num
的最后一次出现的位置i
到数组lastIndex
中,并增加元素num
的出现次数count[num]
。 - 在统计过程中,记录出现次数的最大值
maxCount
。
- 对于数组中的每个元素
-
统计完成后,再次遍历数组
nums
,寻找出现次数等于maxCount
的元素,并计算其对应的最短连续子数组的长度。具体步骤如下:- 对于数组中的每个元素
num
,如果它的出现次数等于maxCount
,则计算它的连续子数组的长度length
,即lastIndex[num] - firstIndex[num] + 1
。 - 不断更新最短连续子数组的长度
minLength
。
- 对于数组中的每个元素
-
最后,返回最短连续子数组的长度
minLength
。