题目:
Given an integer array of size n, find all elements that appear more than ⌊ n/3 ⌋ times.
Note: The algorithm should run in linear time and in O(1) space.
思路:
思路直接看博文https://www.cnblogs.com/grandyang/p/4606822.html就好。我验证了一下里面提到的数学结论:“任意一个数组出现次数大于 n/3 的数最多有两个”。我枚举了
n
∈
[
0
,
99
]
n\in[0,99]
n∈[0,99]的情况,验证了一下这个结论的正确性,如下:
n=0, 一组1个, 最多分成0组
n=1, 一组1个, 最多分成1组
n=2, 一组1个, 最多分成2组
n=3, 一组2个, 最多分成1组
n=4, 一组2个, 最多分成2组
n=5, 一组2个, 最多分成2组
n=6, 一组3个, 最多分成2组
n=7, 一组3个, 最多分成2组
n=8, 一组3个, 最多分成2组
n=9, 一组4个, 最多分成2组
n=10, 一组4个, 最多分成2组
n=11, 一组4个, 最多分成2组
n=12, 一组5个, 最多分成2组
n=13, 一组5个, 最多分成2组
n=14, 一组5个, 最多分成2组
n=15, 一组6个, 最多分成2组
n=16, 一组6个, 最多分成2组
n=17, 一组6个, 最多分成2组
n=18, 一组7个, 最多分成2组
n=19, 一组7个, 最多分成2组
n=20, 一组7个, 最多分成2组
n=21, 一组8个, 最多分成2组
n=22, 一组8个, 最多分成2组
n=23, 一组8个, 最多分成2组
n=24, 一组9个, 最多分成2组
n=25, 一组9个, 最多分成2组
n=26, 一组9个, 最多分成2组
n=27, 一组10个, 最多分成2组
n=28, 一组10个, 最多分成2组
n=29, 一组10个, 最多分成2组
n=30, 一组11个, 最多分成2组
n=31, 一组11个, 最多分成2组
n=32, 一组11个, 最多分成2组
n=33, 一组12个, 最多分成2组
n=34, 一组12个, 最多分成2组
n=35, 一组12个, 最多分成2组
n=36, 一组13个, 最多分成2组
n=37, 一组13个, 最多分成2组
n=38, 一组13个, 最多分成2组
n=39, 一组14个, 最多分成2组
n=40, 一组14个, 最多分成2组
n=41, 一组14个, 最多分成2组
n=42, 一组15个, 最多分成2组
n=43, 一组15个, 最多分成2组
n=44, 一组15个, 最多分成2组
n=45, 一组16个, 最多分成2组
n=46, 一组16个, 最多分成2组
n=47, 一组16个, 最多分成2组
n=48, 一组17个, 最多分成2组
n=49, 一组17个, 最多分成2组
n=50, 一组17个, 最多分成2组
n=51, 一组18个, 最多分成2组
n=52, 一组18个, 最多分成2组
n=53, 一组18个, 最多分成2组
n=54, 一组19个, 最多分成2组
n=55, 一组19个, 最多分成2组
n=56, 一组19个, 最多分成2组
n=57, 一组20个, 最多分成2组
n=58, 一组20个, 最多分成2组
n=59, 一组20个, 最多分成2组
n=60, 一组21个, 最多分成2组
n=61, 一组21个, 最多分成2组
n=62, 一组21个, 最多分成2组
n=63, 一组22个, 最多分成2组
n=64, 一组22个, 最多分成2组
n=65, 一组22个, 最多分成2组
n=66, 一组23个, 最多分成2组
n=67, 一组23个, 最多分成2组
n=68, 一组23个, 最多分成2组
n=69, 一组24个, 最多分成2组
n=70, 一组24个, 最多分成2组
n=71, 一组24个, 最多分成2组
n=72, 一组25个, 最多分成2组
n=73, 一组25个, 最多分成2组
n=74, 一组25个, 最多分成2组
n=75, 一组26个, 最多分成2组
n=76, 一组26个, 最多分成2组
n=77, 一组26个, 最多分成2组
n=78, 一组27个, 最多分成2组
n=79, 一组27个, 最多分成2组
n=80, 一组27个, 最多分成2组
n=81, 一组28个, 最多分成2组
n=82, 一组28个, 最多分成2组
n=83, 一组28个, 最多分成2组
n=84, 一组29个, 最多分成2组
n=85, 一组29个, 最多分成2组
n=86, 一组29个, 最多分成2组
n=87, 一组30个, 最多分成2组
n=88, 一组30个, 最多分成2组
n=89, 一组30个, 最多分成2组
n=90, 一组31个, 最多分成2组
n=91, 一组31个, 最多分成2组
n=92, 一组31个, 最多分成2组
n=93, 一组32个, 最多分成2组
n=94, 一组32个, 最多分成2组
n=95, 一组32个, 最多分成2组
n=96, 一组33个, 最多分成2组
n=97, 一组33个, 最多分成2组
n=98, 一组33个, 最多分成2组
n=99, 一组34个, 最多分成2组
补充对代码的分析。上述博文中没有对代码的实现进行解释,我简单地分析了一下子:这段代码实质上是同时找出两个最多重复出现的数字。每次迭代时,同时对两个数字进行检验。这个题目与169. Majority Element是一类的。这类算法并不是寻找所谓的“众数”,而是有着极为苛刻的条件。 必须保证存在元素符合more than ⌊ n/2 ⌋ times(正好等于一半也可以)
或者more than ⌊ n/3 ⌋ times(正好等于三分之一也可以)
之类的条件才可以把数组中的众数找出来。如果不符合,则算法没有意义。所以,此类题目可以稍稍推广一下,解法应该都是类似的,同时上述的数学结论也可以推广(我用程序简单验证了一下)。比如类似题目可以是:
Given an integer array of size n, find all elements that appear more than ⌊ n/2 ⌋ times.
Note: The algorithm should run in linear time and in O(1) space.
Given an integer array of size n, find all elements that appear more than ⌊ n/3 ⌋ times.
Note: The algorithm should run in linear time and in O(1) space.
Given an integer array of size n, find all elements that appear more than ⌊ n/4 ⌋ times.
Note: The algorithm should run in linear time and in O(1) space.
Given an integer array of size n, find all elements that appear more than ⌊ n/5 ⌋ times.
Note: The algorithm should run in linear time and in O(1) space.
······
Given an integer array of size n, find all elements that appear more than ⌊ n/t ⌋ times.
Note: The algorithm should run in linear time and in O(1) space.
代码实现:
此题目的完整代码如下:
class Solution {
public:
vector<int> majorityElement(vector<int>& nums) {
vector<int> ret;
int a;
int b;
int count1 = 0;
int count2 = 0;
for (int i = 0; i < nums.size(); ++i){
if (nums[i] == a){
++count1;
}else if (nums[i] == b){
++count2;
}else if (count1 == 0){
a = nums[i];
count1 = 1;
}else if (count2 == 0){
b = nums[i];
count2 = 1;
}else{
--count1;
--count2;
}
}
count1 = 0;
count2 = 0;
for (int i = 0; i < nums.size(); ++i){
if (nums[i] == a){
++count1;
}else if (nums[i] == b){
++count2;
}
}
if (count1 > nums.size()/3){
ret.push_back(a);
}
if (count2 > nums.size()/3){
ret.push_back(b);
}
return ret;
}
};
验证数学结论的代码如下:
#include<iostream>
using namespace std;
int main()
{
for (int i = 0; i < 100; ++i) {
cout << "n=" << i << ", 一组" << i / 3 + 1 << "个, 最多分成" << i/(i / 3 + 1) << "组" << endl;
}
return 0;
}
验证推广的数学结论的代码如下:
#include<iostream>
using namespace std;
int main()
{
int t = 6; // 可以自己改几个值试试,结论是可以推广的
for (int i = 0; i < 100; ++i) {
cout << "n=" << i << ", 一组" << i / t + 1 << "个, 最多分成" << i / (i / t + 1) << "组" << endl;
}
return 0;
}