575. 分糖果

题目

Alice 有 n 枚糖,其中第 i 枚糖的类型为 candyType[i]。Alice 注意到她的体重正在增长,所以前去拜访了一位医生。

医生建议 Alice 要少摄入糖分,只吃掉她所有糖的 n / 2 即可(n 是一个偶数)。Alice 非常喜欢这些糖,她想要在遵循医生建议的情况下,尽可能吃到最多不同种类的糖。

给你一个长度为 n 的整数数组 candyType,返回:Alice 在仅吃掉 n / 2 枚糖的情况下,可以吃到糖的 最多 种类数。

示例 1:

输入:candyType = [1,1,2,2,3,3]
输出:3
解释:Alice 只能吃 6 / 2 = 3 枚糖,由于只有 3 种糖,她可以每种吃一枚。

示例 2:

输入:candyType = [1,1,2,3]
输出:2
解释:Alice 只能吃 4 / 2 = 2 枚糖,不管她选择吃的种类是 [1,2]、[1,3] 还是 [2,3],她只能吃到两种不同类的糖。

示例 3:

输入:candyType = [6,6,6,6]
输出:1
解释:Alice 只能吃 4 / 2 = 2 枚糖,尽管她能吃 2 枚,但只能吃到 1 种糖。

提示:

  • n == candyType.length
  • 2 <= n <= 10^4
  • n 是一个偶数
  • -10^5 <= candyType[i] <= 10^5

代码

解法1 排序后查找(费时间省空间)

#include <stdlib.h>
#include <stdio.h>
int cmp(const int *a, const int *b)
{
    return (*(int*)a - *(int*)b);
}

int distributeCandies(int* candyType, int candyTypeSize) {
    int res = 0;
    int lastEatType = -1;
    qsort(candyType,candyTypeSize,sizeof(int),cmp);
    for (int i = 0; i < candyTypeSize; i++)
    {
        if(candyType[i] != lastEatType)
        {
            lastEatType = candyType[i];
            res++;
        }
        if(res >= candyTypeSize / 2)
        {
            break;
        }
    }
    return res;
}

int main(void)
{
    int a[]= {10000,0,10000,0,10000,0,10000,0,10000,0,10000,0};
    int size = sizeof(a) / sizeof(a[0]);
    int ret = distributeCandies(a, size);
    printf("ret = %d\n",ret);
}

代码复杂度分析

  1. 时间复杂度:

    • 主要的计算成本来自 qsort 函数,该函数对 candyType 数组进行排序。qsort 的平均时间复杂度是 (O(nlog n)),其中 (n) 是 candyTypeSize
    • 排序之后,代码遍历排序后的数组一次。这个循环的时间复杂度是 (O(n))
    • 因此,函数的总体时间复杂度主要由排序步骤决定,为(O(nlog n))
  2. 空间复杂度:

    • 空间复杂度主要由 qsort 函数决定,通常需要(O(log n)) 的额外空间用于递归栈。
    • 除此之外,只使用了几个整数 (res, lastEatType, 循环索引 i),这些是(O(1))
    • 因此,整体空间复杂度是(O(log n))

代码拆解

以下是代码的逐步拆解:

  1. 比较函数:

    int cmp(const int *a, const int *b)
    {
        return (*(int*)a - *(int*)b);
    }
    
    • 这是一个比较函数,用于 qsort。它接收两个整数指针作为参数,返回它们的差值,用于决定排序顺序。
  2. 分发糖果函数:

    int distributeCandies(int* candyType, int candyTypeSize) {
        int res = 0;
        int lastEatType = -1;
        qsort(candyType, candyTypeSize, sizeof(int), cmp);
    
    • distributeCandies 函数接收一个整数数组 candyType 和数组的大小 candyTypeSize
    • 初始化结果 res 为 0 和 lastEatType 为 -1。
    • 使用 qsortcandyType 数组进行排序。
  3. 遍历排序后的数组:

        for (int i = 0; i < candyTypeSize; i++)
        {
            if(candyType[i] != lastEatType)
            {
                lastEatType = candyType[i];
                res++;
            }
            if(res >= candyTypeSize / 2)
            {
                break;
            }
        }
        return res;
    }
    
    • 遍历排序后的数组:
      • 如果当前糖果类型与上一个吃过的糖果类型不同,则更新 lastEatType 为当前糖果类型,并将 res 加1。
      • 如果 res 达到或超过糖果总数的一半,则跳出循环。
    • 返回 res,即可以分发的不同糖果类型的数量。

结果

代码1结果

解法2 用数组下标查找(费空间省时间)

int distributeCandies(int* candyType, int candyTypeSize) {
    int res = 0;
    int typeArr[200000] = {0}; // type从-10000 到10000
    for (int i = 0; i < candyTypeSize; i++)
    {
        if(typeArr[candyType[i]+100000 - 1] == 0) // -1防止越界
        {
            typeArr[candyType[i]+100000 - 1] = 1;
            res ++;
        }
        if(res >= candyTypeSize / 2)
        {
            break;
        }
    }
    
    return res;
}

代码复杂度分析

  1. 时间复杂度:

    • 代码遍历数组一次。循环的时间复杂度是 (O(n))
  2. 空间复杂度:

    • 空间复杂度来自于typeArr数组,题目规定范围是-10^5 ~ 10^ 5,因此也可以看作(O(1)),其他的变量都是 (O(1))
    • 因此对于这一题,这个复杂度也是(O(1))

结果

不出所料地比第一种解法优
结果

总结

  • 该函数通过排序和遍历来计算可以分发的最大不同糖果类型数量。
  • 关键步骤是使用 qsort 进行排序,然后遍历已排序数组,确保每种糖果类型只计数一次,直到达到最大可分发数量。
  • 如果对题目分析透彻一点,投机取巧可以省下时间和空间
  • 23
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值