【leetcode】229. Majority Element II

题目:
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, 一组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;
}

参考:
https://www.cnblogs.com/grandyang/p/4606822.html

原创文章 299 获赞 2 访问量 1万+

猜你喜欢

转载自blog.csdn.net/zxc120389574/article/details/106100798