多数投票算法 Majority Vote Algorithm

题目

Given an integer array of size n, find all elements that appear more 
than ? n/3 ? times. The algorithm should run in linear time and in 
O(1) space.

相似题目及多数投票算法

第一眼看到这个题,相信许多人都恩给你联想到另一个题目:

给定一个整数数组,找出出现次数大于 n/2 的那个数。

如果是找出出现次数大于n/2的数,解决这个问题的思路并不难,可以用Map扫描一遍,并且统计出现次数。但是这种方法的时间复杂度虽然是O(N),空间复杂度也相应的是O(N)。还有一种方法是多数投票算法,算法的名字虽然没听说过,但是思路相信大多数人还是知道的。

  1. 如果count==0,则将now的值设置为数组的当前元素,将count赋值为1;
  2. 反之,如果now和现在数组元素值相同,则count++,反之count–;
  3. 重复上述两步,直到扫描完数组。

之前做过的题目都是确定数组中有大于n/2的那个数存在的,所以没有了后边的检查步骤。

思路

看到这题首先想到的是出现次数大于? n/3 ?的数不只有一个,思考了一下,这个数最多有两个,最少一个也没有。所以可以用一个大小为2的数组保存候选结果,最后进行筛选。

然后是候选结果的保存,考察答题者的知识迁移能力,可怜的是我迁移了半天也没移对-,-

这里不说我的错误思路了。直接说解题方法吧。

以nums = [8,8,7,7,7]为例

nums中当前遍历的数 候选数组 count数组
8 [8 , 0 ] [1 , 0]
8 [8 , 0 ] [2 , 0]
7 [8 , 7 ] [2 , 1]
7 [8 , 7 ] [2 , 2]
7 [8 , 7 ] [2 , 3]

一行跟第二行的0是默认初始化的值

 在面试题中经常会出现这样一个题目,给一个数组,其中含有N个非负元素,让你求出数组中出现次数超过一半的数字。

看到这个问题我们首先想到的可能是暴力的解法,那就是将数组排个序,输出中间的元素就行了,因为如果出现次数超过一半的话排完序后中间的那个元素肯定是我们需要求的值。

这样做的话排序的时间复杂度一般来说是O(NlogN),那么有没有时间复杂度为n的算法呢?

    答案当然是有的,有这样的一个算法,Majority Vote Algorithm,他是这样的做的:设置一个计数器count和保存最多元素的变量majority,

  1. 如果count==0,则将now的值设置为数组的当前元素,将majority赋值为1;
  2. 反之,如果majority和现在数组元素值相同,则count++,反之count--;
  3. 重复上述两步,直到扫描完数组。
  4. count赋值为0,再次从头扫描数组,如果素组元素值与majority的值相同则count++,直到扫描完数组为止。
  5. 如果此时count的值大于等于n/2,则返回majority的值,反之则返回-1。
#include 
#include 
#include 

using namespace std;

//超一半的元素
int majorityElement(vector& nums)
{
	int len = nums.size();
	if (len <= 0) return -1;
	int candidate = nums[0], count = 0;
	for (int x : nums)
	{
		if (count == 0)////如果是第一次记录或者当前candidate数为0票,把当前candidate数设定为数组的当前元素  
		{
			candidate = x;
			count = 1;
		}
		else if (candidate == x)//如果数组扫描到的数和当前candidate数相等  
			count++;
		else                    //如果数组扫描到的数和当前candidate数不相等  
			count--;
	}

	count = 0;
	for (int n : nums)
		if (n == candidate)
			count++;
	if (count < (len + 1) / 2) return -1;

	return candidate;
}

int majorityElement_map(vector& nums) {
	unordered_map res_map;

	int len = nums.size();
	if (len <= 0) return -1;
	for (int i = 0; isecond>(len/ 2))
		   res = it->first;
	}
		
	return res;
}



//超1/3的元素  最多有两个候选者
vector majorityElement1_3(vector& nums)
{
	int len = nums.size();
	if (len <= 0) return nums;
	int candidate1 = 0, candidate2 = 0, count1 = 0, count2 = 0;
	for (int x : nums)
	{
		if (x == candidate1) count1++;
		else if (x == candidate2) count2++;
		else
		{
			if (count1 == 0)
			{
				candidate1 = x;
				count1++;
			}
			else if (count2 == 0)
			{
				candidate2 = x;
				count2++;
			}
			else
			{
				count1--;
				count2--;
			}
		
		}
	}

	count1 = count2 = 0;
	for (int x : nums)
	{
		if (x == candidate1) count1++;
		else if(x == candidate2) count2++;
	}
	vector res;
	if (count1 > len / 3) res.push_back(candidate1);
	if (count2 > len / 3) res.push_back(candidate2);

	return res;

}

vector majorityElement_map1_3(vector& nums) {
	unordered_map res_map;
	vector res;
	int len = nums.size();
	if (len <= 0) return nums;
	for (int i = 0; isecond>(len / 3))
			res.push_back(it->first);
	return res;
}

int main()
{
	vector vec{ 1, 1, 1, 2, 3, 3, 3,3,4,3,3,3};
	cout << majorityElement(vec) << endl;
	cout << majorityElement_map(vec) << endl;



	vector vec1 = majorityElement1_3(vec);
	for (int i : vec1)
		cout << i << " ";
	cout << endl;

	vector vec2 = majorityElement_map1_3(vec);
	for (int i : vec2)
		cout << i << " ";
	cout << endl;

	system("pause");
	return 0;
}





你可能感兴趣的:(LeetCode)