摩尔投票算法解决leetcode 169, 229

1、leetcode 169

给定一个大小为 n 的数组,找到其中的多数元素。多数元素是指在数组中出现次数大于 ⌊ n/2 ⌋ 的元素。
你可以假设数组是非空的,并且给定的数组总是存在多数元素。

1.1其他方法

 思路:对于这个题,常见的方法时使用hashmap对数据每个元素进行统计,然后计算除每个元素的个数,最后进行提取就ok,这个方法需要二外的空间。
 还有一种方法是直接对其进行排序,(快排或者冒泡),排完序之后直接返回v[v.size()/2],这个中间元素就一定是要求的元素。
代码:这里我们用快排,将其转换为求topk的问题。(求第v.size()/2+1大的元素)

class Solution {
public:
void quick_sort(vector<int>& nums, int left, int right, int k)
{
	//从大到小排列
	if (left >= right)
		return;
	int i = left, j = right;
	while (i <j)
	{
		//从right向左找出大于nums[left]
		while (i < j&&nums[j] <= nums[left])
		{
			j--;
		}
		//从left向右找出小于nums[left]
		while (i < j&&nums[i] >= nums[left])
		{
			i++;
		}
		if (i < j)
			swap(nums[i], nums[j]);
	}
	swap(nums[left], nums[i]);
	int num = i - left + 1;
	if (num == k)
		return;
	if (num > k)
		quick_sort(nums, left, i - 1, k);
	else
		quick_sort(nums, i + 1, right, k - num);
}
    int majorityElement(vector<int>& nums) {
        //复习快排,转换为求topK的问题
        int n=nums.size();
        if(n==1)
        return nums[0];
      quick_sort(nums,0,nums.size()-1,nums.size()/2+1);
      return  nums[nums.size()/2];
    }
};

或者是调用nth_element函数,

template <class RandomAccessIterator>
  void nth_element (RandomAccessIterator first, RandomAccessIterator nth,
                    RandomAccessIterator last);

重新排列[first,last)范围内的元素,以使位于第n个位置的元素是按真实的顺序的元素(即默认第n个元素的第n+1大的数)。其他元素没有任何特定的顺序,只是第n个元素之前的元素都不比其大,而第n个元素的元素都不小于。底层还是使用的快排和选择排序的结合。
用法:

void main()
{
	vector<int> v = { 7,2,1,5,0,6,4,3 };
	nth_element(v.begin(), v.begin() + 3, v.end());
	cout << "第3小是:" << v[2] << endl;
}
int majorityElement(vector<int>& nums) {

    if(nums.size()==0)
    return -1;
   // sort(nums.begin(),nums.end());   
   nth_element(nums.begin(),nums.begin()+nums.size()/2,nums.end());
    return nums[nums.size()/2];
}

1.2 摩尔投票

思路:可以理解为同归于尽算法,有候选者cond,其num=0,当num=0时,从新选择候选者,cond=nums[i],num=1,当cond !=nums[i],num–,当cond ==nums[i],num++。其实就是不停的抵消,因为总有一个元素时大于n/2的,所以最后总能剩下一个元素时该元素,当要注意最后的num并不等于所求元素的个数。因为会被之前的元素抵消。
在这里插入图片描述

class Solution {
public:
    int majorityElement(vector<int>& nums) {
            int n=nums.size();
        if(n==0)
        return -1; 
        int count=0,cand=nums[0];
        for(int i=0;i<n;i++)
        {
            if(count==0)
            {
                count++;
                cand=nums[i];
                continue;
            }
           if(cand==nums[i])
               count++;
            else
              count--;
        }  
        return cand;
    }
};

2、leetcode 229

229. 求众数 II 给定一个大小为 n 的数组,找出其中所有出现超过 ⌊ n/3 ⌋ 次的元素。

2.1 其他方法

说明: 要求算法的时间复杂度为 O(n),空间复杂度为 O(1)。
思路:这个题的思路和上个题的思路是一样的,也是可以使用map或者快排(这里快排求出nums[n/3]和nums[]),但注意这个题不保证一定存在这个数,且最多存在2个超过 ⌊ n/3 ⌋ 次的元素,所以最后要进行判断。

class Solution {
public:
    vector<int> majorityElement(vector<int>& nums) {
         if(nums.size()==0)
       return {};
       int n=nums.size();
      sort(nums.begin(),nums.end());
     int cond1=nums[n/3],num1=0;
     int cond2=nums[2*n/3],num2=0;
     int cond3=nums[nums.size()-1],num3=0;
     for(auto e:nums)
     {
         if(e==cond1) num1++;
         else if(e==cond2) num2++; 
         else if(e==cond3) num3++; 
     }
       vector<int>  res;
      if(num1>(n/3))
        res.push_back(cond1);
        if(num2>(n/3))
        res.push_back(cond2);
        if(num3>(n/3))
        res.push_back(cond3);
    return res;
    }
};

2.2 摩尔投票

思路:选择两个候选者,cond1和cond2,个数分别为num1,num2
则再循环判断的时候,存在四种情况:
1、果cond1==e,则候选者1的 票数++;
2、如果cond2==e,则候选者2 的 票数++;
3、如果num1==0,cond1候选者更新为e;
4、如果num2==0,cond2候选者更新为e;
最后会有这么几种可能:有2个大于n/3,有1个大于n/3,有0个大于n/3,因为遍历结束后一定会选出了两个候选人,但是这两个候选人是否满足>n/3,还需要再遍历一遍数组,找出两个候选人的具体票数,因为题目没有像169题保证一定有。

vector<int> majorityElement(vector<int>& nums) {
	int n = nums.size();
	vector<int>  res;
	if (n == 0)
		return {};
	// 定义两个候选者和它们的票数
	int cond1 = 0, cond2 = 0;
	int num1 = 0, num2 = 0;
	for (auto e : nums)
	{
		//如果cond1==e,则候选者1 票数++
		if (cond1 == e)
		{
			num1++;
			continue;
		}
		//如果cond2==e,则候选者2 票数++
		if (cond2 == e)
		{
			num2++;
			continue;
		}
		//如果num1=0,cond1候选者更新为e
		if (num1 == 0)
		{
			cond1 = e;
			num1++;
			continue;
		}
		//如果num1=0,cond2候选者更新为e
		if (num2 == 0)
		{
			cond2 = e;
			num2++;
			continue;
		}

		num1--;
		num2--;
	}
	num1 = num2 = 0;
	for (auto e : nums)
	{
		if (cond1 == e)
			num1++;
		else if (cond2 == e)
			num2++;
	}
	if (num1 > (n / 3))
		res.push_back(cond1);
	if (num2 > (n / 3))
		res.push_back(cond2);
	return res;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值