问题:在长度为n的数组中找出重复次数超过n/2的数(假设一定存在)
摩尔投票法基于这样一个事实,当一个数的重复次数超过数组长度的一半,每次将两个不相同的数删除,最终剩下的就是要找的数。
摩尔投票法的代码实现并不是真的要删除数组里的数,只是把遍历过程当作一个删除过程。
使用一个虚拟数组存放还未和不同数字一起删除的数,这个数组只能有若干个同一数字,不可能存在不同的数,因为如果存在不同的数就会被删去,而不会放到此数组中。
当数组遍历到当前元素时,若虚拟数组为空,就将当前元素加进去;若虚拟数组非空,就比较当前元素是否和虚拟数组中的元素相同,如果不同就删去虚拟数组中的一个元素,同时当作当前元素也被删除,接着遍历下一元素,这样就相当于一对不同的数字被删除,如果相同,就把当前元素加到虚拟数组中。最终遍历完数组,虚拟数组中的元素就是要找的元素。
由于虚拟数组中只会存在若干个相同元素,那么可以仅用两个变量表示这个虚拟数组,一个变量存值,另一个变量存放个数。
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; //输出
}
};