从零开始刷leetcode数组的“度”C语言编程解答

这篇文章介绍了一种使用哈希表解决的问题,给定一个整数数组,目标是找到具有最大度(元素出现频数的最大值)的最短连续子数组。通过遍历数组计算元素的出现次数、首次和最后出现位置,找到满足度的最短子数组长度。
摘要由CSDN通过智能技术生成

描述

给定一个非空且只包含非负数的整数数组 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

  1. 定义了一个结构体 HashTable 用来表示哈希表中的每个元素,包括了键值 key、出现次数 num,以及第一次出现的位置 add1 和最后一次出现的位置 add2

  2. findShortestSubArray 函数中,首先创建了一个指向 HashTable 结构体的指针 hanshTable,用于存储哈希表。

  3. 然后,遍历输入数组 nums,对于数组中的每个元素,如果哈希表中已经存在该元素,则更新其出现次数 num 和最后一次出现位置 add2;否则,在哈希表中添加该元素,并初始化其出现次数为1,第一次和最后一次出现位置为当前遍历的位置。

  4. 接下来,遍历完数组后,得到了哈希表中每个元素的出现次数以及第一次和最后一次出现的位置。

  5. 然后,使用变量 maxNum 来记录数组的度,即出现次数的最大值;使用变量 minLen 来记录最短连续子数组的长度,初始化为0。

  6. 再次遍历哈希表,对于每个元素,如果其出现次数等于数组的度 maxNum,则更新最短连续子数组的长度 minLen,取当前元素的最后一次出现位置减去第一次出现位置再加1的最小值。

  7. 最后,返回变量 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 

  1. findShortestSubArray 函数的定义:

    • 参数 nums 是一个指向整数数组的指针,表示输入的非空且只包含非负数的整数数组。
    • 参数 numsSize 表示数组 nums 的长度。
  2. 在函数内部,定义了三个数组 countfirstIndexlastIndex 来分别记录每个元素的出现次数、第一次出现的位置和最后一次出现的位置。这三个数组的索引对应数组 nums 中的元素值。

  3. 使用一个循环遍历数组 nums,统计每个元素的出现次数、第一次出现的位置和最后一次出现的位置。具体步骤如下:

    • 对于数组中的每个元素 num,如果它是第一次出现,则记录其第一次出现的位置 i 到数组 firstIndex 中。
    • 每次更新元素 num 的最后一次出现的位置 i 到数组 lastIndex 中,并增加元素 num 的出现次数 count[num]
    • 在统计过程中,记录出现次数的最大值 maxCount
  4. 统计完成后,再次遍历数组 nums,寻找出现次数等于 maxCount 的元素,并计算其对应的最短连续子数组的长度。具体步骤如下:

    • 对于数组中的每个元素 num,如果它的出现次数等于 maxCount,则计算它的连续子数组的长度 length,即 lastIndex[num] - firstIndex[num] + 1
    • 不断更新最短连续子数组的长度 minLength
  5. 最后,返回最短连续子数组的长度 minLength

  • 7
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

多宝气泡水

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值