1. 程式人生 > 其它 >劍指 offer程式碼解析——面試題29陣列中出線次數超過一半的數字

劍指 offer程式碼解析——面試題29陣列中出線次數超過一半的數字

題目:陣列中有一個數字出現的次數超過陣列長度的一半,請找出這個數字。

分析:本題最直觀的思路就是分別統計陣列中每個數出現的次數,然後求出最大值,判斷是否超過陣列長度的一半。這種方法的時間複雜度為O(n^2),在面試中,第一反應想到的方法往往不是最佳答案,下面我們來尋求更加高效的方式。

一個數出現的次數如果超過陣列長度的一半,那麼可以得出以下結論:

1.如果把超過陣列長度一半的數整理在一起形成陣列b,那麼不管把b放在陣列的什麼位置,陣列的中位數一定在b中。

2.個數超過陣列長度一半的數最多隻有一個。

基於上述兩點結論,我們可以首先將陣列排序,使得超過陣列長度一半的那些數靠在一起,然後取排序後陣列的中位數,最後判斷該數的長度是否超過陣列長度的一半。程式碼如下:

import offer8.QuickSort;

/**
 * 題目:陣列中有一個數字出現的次數超過陣列長度的一半,請找出這個數字。
 * @author 大閒人柴毛毛
 * @date 2016年3月16日
 */
public class CountNumber {

	/**
	 * 分析:本題最直觀的思路就是分別統計陣列中每個數出現的次數,然後求出最大值,判斷是否超過陣列長度的一半。
	 * 這種方法的時間複雜度為O(n^2),在面試中,第一反應想到的方法往往不是最佳答案,下面我們來尋求更加高效的方式。
	 */
	
	/**
	 * 一個數出現的次數如果超過陣列長度的一半,那麼可以得出以下結論:
	 * 1.如果把超過陣列長度一半的數整理在一起形成陣列b,那麼不管把b放在陣列的什麼位置,陣列的中位數一定在b中。
	 * 2.個數超過陣列長度一半的數最多隻有一個。
	 * 基於上述兩點結論,我們可以首先將陣列排序,使得超過陣列長度一半的那些數靠在一起,然後取排序後陣列的中位數,最後判斷該數的長度是否超過陣列長度的一半。
	 * 程式碼如下:
	 */
	
	/**
	 * 獲取陣列中出現次數超過一半的那個數
	 * @param a 輸入的陣列
	 * @return 返回出現次數超過一半的那個數(返回-1表示函數出錯)
	 */
	public static int countNumber(int[] a){
		//若陣列為空
		if(a==null || a.length<=0){
			System.out.println("陣列為空!");
			return -1;
		}
		
		//對陣列排序
		QuickSort.QuickSort(a);
		
		//獲取中位數
		int mid = a[a.length/2];
		
		//計算中位數出現的次數
		int count = 0;
		for(int i=0;i<a.length && a[i]<=mid;i++){
			if(a[i]==mid)
				count++;
		}
		
		//判斷中位數出現的次數是否超過陣列長度的一半
		if(count>=a.length/2)
			return mid;
		else
			return -1;
	}
	
	
	
	/**
	 * 測試
	 */
	public static void main(String[] args){
		int[] a = {3,1,3,2,3,2,3,2,2,3,5,3,4,2,3,3};
		System.out.println(countNumber(a));
	}
}