高效寻找数组中的众数——摩尔投票法

问题:在长度为n的数组中找出重复次数超过n/2的数(假设一定存在)

摩尔投票法基于这样一个事实,当一个数的重复次数超过数组长度的一半,每次将两个不相同的数删除,最终剩下的就是要找的数。

摩尔投票法的代码实现并不是真的要删除数组里的数,只是把遍历过程当作一个删除过程。

使用一个虚拟数组存放还未和不同数字一起删除的数,这个数组只能有若干个同一数字,不可能存在不同的数,因为如果存在不同的数就会被删去,而不会放到此数组中。

当数组遍历到当前元素时,若虚拟数组为空,就将当前元素加进去;若虚拟数组非空,就比较当前元素是否和虚拟数组中的元素相同,如果不同就删去虚拟数组中的一个元素,同时当作当前元素也被删除,接着遍历下一元素,这样就相当于一对不同的数字被删除,如果相同,就把当前元素加到虚拟数组中。最终遍历完数组,虚拟数组中的元素就是要找的元素。

由于虚拟数组中只会存在若干个相同元素,那么可以仅用两个变量表示这个虚拟数组,一个变量存值,另一个变量存放个数。

leetcode 面试题 17.10. 主要元素

leetcode 169 多数元素

class Solution {
    
    
public:
	int majorityElement(vector<int>& nums) 
	{
    
    
		int temp = nums[0], count =1;//虚拟数组为空,加入当前元素
		int nums_size = nums.size();
		for (int i = 1; i < nums_size; i++)
		{
    
    
			if (nums[i] == temp)
				count++;
				//数组非空,当前元素与虚拟数组元素相同,加入当前元素
			else
			//数组非空,当前元素与虚拟数组元素不同,删除一对不相同的元素
				count--;
			if (count == 0)
			{
    
    //虚拟数组为空,加入当前元素
				temp = nums[i];
				count++;
			}
		}
		count = 0;
		int t = (nums_size) / 2 + 1;
		for (int i = 0; i < nums_size; ++i)
		{
    
    //要验证答案
			if (nums[i] == temp)
				count++;
			if (count == t) return temp;
		}
		return -1;
	}

};

类似的问题: 在长度为n的数组中找出重复次数超过n/3的数(不一定存在)。

容易知道,重复次数超过数组长度1/3的数最多有两个。同样的思路,使用两个虚拟数组,每次删除三个不同的数,最终虚拟数组中的两个数就是可能的答案,此时再遍历一遍数组,做一个验证即可。

class Solution {
    
    
public:
	int majorityElement(vector<int>& nums) 
	{
    
    
		int x, y, x_count=0, y_count=0;
		int nums_size = nums.size();
		for (int i = 0; i < nums_size; i++)
		{
    
    
			if (x == nums[i])x_count++;
			else if (y == nums[i])y_count++;
			else if (x_count == 0) x = nums[i], x_count = 1;
			else if (y_count == 0) y = nums[i], y_count = 1;
			else x_count--, y_count--;
		}
		x_count = 0, y_count = 0;
		for (int i = 0; i < nums_size; ++i)
		{
    
    
			if (x == nums[i])
				x_count++;
			else if (y == nums[i])
				y_count++;
		}
		if (x_count > nums_size / 3)
			cout << x << endl;//输出
		if (y_count > nums_size / 3)
			cout << y << endl; //输出
	}

};

猜你喜欢

转载自blog.csdn.net/weixin_45605341/article/details/108315663