火柴拼图
问题描述:牛妹有n根火柴,她想用这些火柴去拼正三角形或者正四边形。牛妹想让最后拼出的总面积尽可能大的,请你帮帮她。 返回一个Vector,Vector中存有两个数字。其中最大面积
示例
示例
输入:4,[1,1,1,1]
返回值:[0,1]
说明:构成一个边长为1的正四边形面积总和最大,值为1。所以Vector[0]=0,Vector[1]=1
方法一
思路分析
因为要构成正三角形或者正四边形,那么首先对给定的火柴,对不同长度的火柴进行计数统计,对不同长度的火柴,先判断火柴数是否大于等于四,如果大于等于四,那么可以构成正四边形,因此计算该正四边形的面积,之后更新该长度的火柴数;接着判断火柴数是否大于等于3,如果是,那么可以构成正三角形,因此计算该正三角形的面积,该长度的火柴已经无法构成正三角形或者正四边形,因此不做更新。具体过程如下:- 首先找到给定火柴数组中长度最大的火柴长度变量m
- 构建存储不同长度火柴的统计数组,其下标对应长度,数组值表示对应长度的火柴数
- 从最大长度的火柴开始遍历,先判断是否构成正四边形,并计算构成正四边形的数量以及面积,之后判断是否构成正三角形,并计算正三角形的面积
- 遍历结束
图解
输入:[1,1,1,2,2,2,2,3,4,5,5,5,5,5,5,5,6,6,6]
遍历过程如下:
C++核心代码
class Solution { public: /** * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可 * * * @param n int整型 n * @param Stick int整型vector Stick * @return long长整型vector */ vector<long> MaxArea(int n, vector<int>& Stick) { // write code here int length_stick = 0; vector<long>res(2); vector<int>a(100010,0); for(int i=0;i<n;i++) { if(length_stick<Stick[i]) length_stick=Stick[i]; a[Stick[i]]++;//a[k]表示该长度对应的数量,这也是记录m的原因 } for(int i=1;i<=length_stick;i++) { if(a[i]>=4)//首先判断能构成正四边形 { int num = a[i]/4;//最多构成正四边形的个数 a[i] -= num*4;//更新构成正四边形后的火柴数 res[1] += (long)i*i*num;//记录面积 } if(a[i]>=3)//判断是否能构成正三角形,如果可以只能构成一个 { res[0] += (long)i*i; } } return res; } };
复杂度分析
- 时间复杂度:首先循环遍历数组找到长度最长的火柴长度$max(Stick)$,时间复杂度为$O(n)$,遍历以此数组统计不同长度火柴对应的数量,时间复杂度为$O(n)$,然后对统计得到的数组进行遍历,时间复杂度为$O(max(Stick))$,因此时间复杂度为$O(n+max(Stick))$
- 空间复杂度:设置一个长度为$max(Stick)$的数组用于存储不同长度火柴对应的数量,因此空间复杂度为$O(max(Stick))$
方法二
思路分析
在方法一的基础上,为了降低空间复杂度与时间复杂度,因此我们可以使用map数据容器存储不同长度对应的火柴数量,这样就不需要找到长度最长的火柴。减少一次循环统计。C++核心代码
class Solution { public: /** * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可 * * * @param n int整型 n * @param Stick int整型vector Stick * @return long长整型vector */ vector<long> MaxArea(int n, vector<int>& Stick) { // write code here map<long, long> a; vector<long>res(2,0); for (int i = 0; i < n; i++)//将火柴长度以及对应的数量存入map { if (a.end() != a.find(Stick[i])) a[Stick[i]]++; else a.insert(pair<int, int>(Stick[i], 1)); } for (auto it : a)//遍历map { if(it.second>=4)//尽可能先组成正四边形 { int p = it.second/4;//组成正四边形的个数 res[1] += (long)(it.first)*(it.first)*p; it.second -= p*4;//更新组成四边形后的火柴数 } if(it.second>=3)//计算是否可以构成正三角形 { res[0] += (long)(it.first)*(it.first); } } return res; } };
复杂度分析
- 时间复杂度:循环遍历数组统计不同长度火柴的数量存入map中,时间复杂度为$O(n)$,循环遍历map,时间复杂度为$O(kind(Stick))$,其中$kind(Stick)$表示数组中按照长度对火柴的分类数量
- 空间复杂度:设置一个统计不同长度火柴的数量的容器,其大小为Stick中按照长度分类火柴的种类,空间复杂度为$O(kind(Stick))$