2021/11/01每日一题
2021/11/1 6:10:23
本文主要是介绍2021/11/01每日一题,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
力扣:575. 分糖果
难度 简单
题目描述:
给定一个偶数长度的数组,其中不同的数字代表着不同种类的糖果,每一个数字代表一个糖果。你需要把这些糖果平均分给一个弟弟和一个妹妹。返回妹妹可以获得的最大糖果的种类数。
示例 1:
输入: candies = [1,1,2,2,3,3] 输出: 3 解析: 一共有三种种类的糖果,每一种都有两个。 最优分配方案:妹妹获得[1,2,3],弟弟也获得[1,2,3]。这样使妹妹获得糖果的种类数最多。示例 2 :
输入: candies = [1,1,2,3] 输出: 2 解析: 妹妹获得糖果[2,3],弟弟获得糖果[1,1],妹妹有两种不同的糖果,弟弟只有一种。这样使得妹妹可以获得的糖果种类数最多。注意:
- 数组的长度为[2, 10,000],并且确定为偶数。
- 数组中数字的大小在范围[-100,000, 100,000]内。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/distribute-candies
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
这道题的解法有很多种,其中最高效的就是求出糖果种类数与总数的一半进行比较。顺着这个思路可以写出很多种不同的代码,以下就是本人第一次提交的代码:
class Solution { public: int distributeCandies(vector<int>& candyType) { set<int> s; for (auto n : candyType) { s.insert(n); } return s.size() > candyType.size() / 2 ? candyType.size() / 2 : s.size(); } };
也可以写作:
class Solution { public: int distributeCandies(vector<int>& candyType) { return min(set<int>(candyType.begin(), candyType.end()).size(), candyType.size() / 2); } };
思路很清晰:
- 将
vector
中的元素放入set
中去。 - 利用
set
的特性(元素无重复)可以直接调用size
方法得到长度,同时就是糖果种类数。 - 判断妹妹得到的最大糖果种类。
但是这种写法的用时和内存的情况是308ms/117.3MB,超过了17.264%/16.616%,非常不满意。
翻看了一下评论区,发现了一种写法:
Duge:
执行用时:156 ms, 在所有 C++ 提交中击败了92.13%的用户
内存消耗:79.7 MB, 在所有 C++ 提交中击败了95.98%的用户
统计糖果种类和重复的数量,重复糖果大于等于一半,妹妹可获得全部种类;小于一半,从剩余的糖果中补充给弟弟,妹妹获得种类则减去补充的数量
class Solution { public: int distributeCandies(vector<int>& candyType) { sort(candyType.begin(), candyType.end()); int type = 1, same = 0,n = candyType.size(), cur = candyType[0]; for(int i = 1; i < n; i++) { if(candyType[i] != cur) { type++; cur = candyType[i]; } else { same++; } } if(same >= n / 2) return type; return type - (n / 2 - same); } };
大致的思路是一样的:
- 计算种类。
- 判断最大种类数.
但是他计算种类的方式却是先排序,再遍历,所以自己也按照这种思路写了一遍:
class Solution { public: int distributeCandies(vector<int>& candyType) { sort(candyType.begin(), candyType.end()); int type = 1, candy = candyType[0]; for (auto candies : candyType) { if (candies != candy) { type++; candy = candies; } } return min(type, (int)candyType.size() / 2); } };
这种写法的用时和内存的情况是106ms/78.8MB,超过了89.902%/88.274%,比Duge差了一点,分析之后认为这一点是因为使用的循环体是 for-in
循环,是从第 \(0\) 个元素开始遍历的,而且还会产生额外的内存开销,而且 min
函数也可能在重载过程中有内存的开销,导致最终的结果没有Duge好。
但是这种思路理论上是比第一种思路耗时更长,因为排序的时间复杂度为 \(O(n^2)\) 到 \(O(\log{n})\) 之间(平均时间复杂度为 \(O(n\log{n})\) ),而第一种方法的复杂度只有 \(O(n)\),所以理论上的成绩两者应该是相反的。
但是如果深入到底层去看的话,将 vector
转换为 set
的实质就是将每个元素依次插入 set
,这也就是为什么第一种思路的两种写法运行结果几乎相同。而每一次的插入都必然会对现有的元素进行遍历以判断重复,所以需要 \(\frac{n(n+1)}{2}\)的时间,而这个时间甚至还没有计算重新为 set
分配空间等操作所花费的时间。所以第一种思路的执行用时更多。
而且由于新定义了一个 set
,内存的开销平均增加了 \(\frac{n}{2}\) ,所以内存消耗也更多。
这篇关于2021/11/01每日一题的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-06-26结对编程到底难不难?答案在这里
- 2024-06-19《2023版Java工程师》课程升级公告
- 2024-06-15matplotlib作图不显示3D图,怎么办?
- 2024-06-1503-Loki 日志监控
- 2024-06-1504-让LLM理解知识 -Prompt
- 2024-06-05做软件测试需要懂代码吗?
- 2024-06-0514-ShardingSphere的分布式主键实现
- 2024-06-03为什么以及如何要进行架构设计权衡?
- 2024-05-31全网首发第二弹!软考2024年5月《软件设计师》真题+解析+答案!(11-20题)
- 2024-05-31全网首发!软考2024年5月《软件设计师》真题+解析+答案!(21-30题)