[剑指Offer]数组中出现次数超过一半的数字

题目描述

数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。例如输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}。由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2。如果不存在则输出0。

分析 :

    思路1:首先我们相当的应该就是遍历,判断每个数出现的次数。即双层循环,判断每个数出现的次数,如果有一个数字出现次数超过一般的数字,则输出。若遍历完没有找到,则输出0。时间复杂度为O(n^2)

    思路2:使用map将数据存于map,然后遍历map, 找到value值超过一半的数字。缺点:需要额外空间。

    接下来介绍剑指offer中提到的两种解法。

   思路3:最直观的做法是排序(快速排序/STL中的sort())后找中间的数即可,但时间复杂度为O(NlgN)。最后遍历一遍,判断找到的 数是否是出现次数超过一半的数字。

   思路4:数组中出现次数超过一半的数字,如果存在,则这个数出现的次数肯定比其他数字出现总数多,所以易定义两个变量,从第一个数开始找,并记录第一个数为result为需要找的数,它出现的次数初始化为times=1; 以后只要找到和result相等的数times++, 否则times-- .times等于0的时候,改变result等于当前指向的数,继续找。最后遍历一遍,判断找到的 数是否是出现次数超过一半的数字。

实现

    这里仅仅介绍后两种实现方法。

1. 排序后找中位数(这里可以使用快排自已查找,也可以使用sort().STL中的算法)

//方法1:基于快速排序
	//Partion要选择一个基准值 
	int Partion(vector<int>& number, int left, int right)
	{
		int begin = left, end = right;
		int key = number[right];

		while(begin < end)
		{
			//begin找大于
			while(begin < end && number[begin] <= key)
			{
				++begin;
			}

			//end找下于
			while(begin < end && number[end] >= key)
			{
				--end;
			}
			swap(number[begin], number[end]);
		}
		swap(number[begin],number[right]);

		return begin;
	}

	int MoreThanHalfNum2(vector<int> numbers) {
		int len = numbers.size();
		if(len <=0 )
		{
			return 0;
		}
		int middle = len/2;
		int div = Partion(numbers, 0,len-1);
		int start = 0;
		int end = len-1;

		while(div != middle)
		{
			if(div > middle)
			{
				end = div-1;
				div = Partion(numbers, start, end);
			}
			else
			{
				start = div+1;
				div = Partion(numbers,start ,end);
			}
		}
		int result = numbers[middle];

		//检查是否超过了一半
		int count = 0;
		for(int i=0; i<len; ++i)
		{
			if(numbers[i] == result)
			{
				count++;
			}
			if(count > len/2)
			{
				return result;
			}
		}
		return 0;
    }

//方法2:STL中的sort
//使用sort
	 int MoreThanHalfNum1(vector<int> numbers) {
        int len = numbers.size();
        if(len <= 0)
        {
            return 0;
        }
        
        sort(numbers.begin(), numbers.end());
        int result = numbers[len/2];
        int count = 0;
        for(int i=0; i<len; i++)
        {
            if(numbers[i] == result)
            {
                count++;
            }
            
             if(count > len/2)
            {
                return result;
            }
        }
        return 0;
    }

2. 定义两个变量,这种方法不易想到,而且不易理解。但是需要记住的是数组中出现次数超过一半的数字,如果存在,则这个数出现的次数肯定比其他数字出现总数多。

//数组中出现次数超过一般的数字(定义两个变量)
	//方法2:利用数组的特点进行求解
    int MoreThanHalfNum_Solution(vector<int> numbers) 
	{
		int len = numbers.size();
		if(len <= 0)
		{
			return 0;
		}

		int result = numbers[0];
		int count = 1;

		for(int i = 1; i < len; ++i)
		{
			if(numbers[i] == result)
				count ++;
			else if(count == 0)
			{
				result = numbers[i];
				count = 1;
			}
			else
				count --;
		}

		//检查是否超过了一半
		count = 0;
		for(int i=0; i<len; ++i)
		{
			if(numbers[i] == result)
			{
				count++;
			}
			if(count > len/2)
			{
				return result;
			}
		}

		return 0;
    }

总结:数组中出现次数超过的一半的数字,需要记住1. 这个数字出现的次数,肯定比其他总数多。2. 排序后,前部分的数字均为这个数字。基于以上两点,可以相当最优方法进行求解。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章