牛牛的和平年代
问题描述
我们定义一个整数可重集合是好的,当且仅当对于集合中任意两个元素 a, b () ,所有满足 的元素 c 都在集合中出现过。 现在,给你一个数组 mSet,你需要做的是,对于这个数组的每一个前缀,判断这个前缀是不是一个好的集合。所以,你将计算出的是一个数组,为布尔类型。
示例
输入:[3,5,4,6]
返回值:[true,false,true,true]
说明:第一个前缀只有一个元素3,按照好的集合的定义,它显然是连续的。
第二个前缀有一个3和一个5,位于3和5之间的元素4却不在集合中,所以它不是连续的。
第三个前缀添加了一个4,弥补了第二个集合缺少4的问题,所以它是好的。
第四个前缀新增了一个6,依旧连续。
第二个前缀有一个3和一个5,位于3和5之间的元素4却不在集合中,所以它不是连续的。
第三个前缀添加了一个4,弥补了第二个集合缺少4的问题,所以它是好的。
第四个前缀新增了一个6,依旧连续。
方法一
思路分析
设置一个数组,,每次添加一个元素进去构成该位置下的前缀,然后对前缀数组元素进行排序,如果两个前后的数不同而且相差不为1,那么可以判断前缀不连续,否则表示该位置下的前缀连续,不断的添加新元素到前缀数组中,直到添加完所有的元素。
图解
C++核心代码
class Solution { public: /** * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可 * * 检查数组的每个前缀是不是一个好的集合 * @param mSet int整型vector * @return bool布尔型vector */ vector<bool> continuousSet(vector<int>& mSet) { // write code here int n=mSet.size(); vector<bool> res(n,false); if (n==0) return res; vector<int> array; for(int i=0;i<n;i++) { array.push_back(mSet[i]);//每次将一个元素放入array sort(array.begin(),array.end());//对前缀排序 int ans=0; int nn=array.size(); for(int j=1;j<nn;j++) { if(array[j]-array[j-1]!=1&&array[j]!=array[j-1]) {////对排序的前缀判断是否连续,如果两个前后的数不同而且相差不为1,那么可以判断前缀不连续 res[i]=false; ans=1; } } if(ans==0) res[i]=true; } return res; } };复杂度分析
- 时间复杂度:首先循环遍历给定数组,每次添加一个元素进行排序,时间复杂度为$O(n \log n)$,每次排序后的比较次数为n次,总的时间复杂度为
- 空间复杂度:借助于一个辅助数组存储前缀元素,空间复杂度为$O(n)$
方法二
思路分析
方法一中需要对添加元素后的前缀数组进行重新排序,而后对排序后的前缀元素进行比较,前后的元素如果不相同那么必须相差1,这其中对数组的排序与比较会花费较多的时间,因此将每次添加的数组元素存储到map结构中,并且记录到当前情况下的前缀中的最大值与最小值,如果到当前位置添加的不同元素个数等于最大值减去最小值加一,那么证明该位置下的前缀数组是连续的。
C++核心代码
class Solution { public: /** * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可 * * 检查数组的每个前缀是不是一个好的集合 * @param mSet int整型vector * @return bool布尔型vector */ vector<bool> continuousSet(vector<int>& mSet) { // write code here int n=mSet.size(); vector<int> dp(n,0);//用于存储set(mSet[:i])的长度 vector<bool> res(n,false); if (n==0) return res; dp[0]=1; for(int i=1;i<n;i++) { vector<int>::const_iterator First = mSet.begin(); vector<int>::const_iterator Second = mSet.begin() + i+1; vector<int> a(First, Second); dp[i]=count(a); } int set_min=mSet[0]; int set_max=mSet[0]; res[0]=true; for(int i=1;i<n;i++) { set_min=min(set_min,mSet[i]); set_max=max(set_max,mSet[i]); if(set_max-set_min+1==dp[i])//前缀是否连续 res[i]=true; else res[i]=false; } return res; } int count(vector<int>& a) { sort(a.begin(),a.end());//快速排序 int count = 1;//统计不重复元素数 for(int i = 1;i<a.size();i++) {//第一个元素必然要计数 if(a[i]!=a[i-1]) {//和前一个元素重复则不计数 count++; } } return count; } };复杂度分析
- 时间复杂度:计算数组中从开始位置到不同位置下的不重复元素的个数,时间复杂度为$O(n^2 \log n)$,遍历数组元素时找到当前位置下的前缀元素中的最大值与最小值,因此时间复杂度为$O(n^2 \log n)$
- 空间复杂度:借助于一个大小为$n$的数组存储给定数组中开始位置到当前位置的不重复的元素个数,空间复杂度为$O(n)$