[劍指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. 排序後,前部分的數字均爲這個數字。基於以上兩點,可以相當最優方法進行求解。

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