題目描述:
數組中有一個數字出現的次數超過數組長度的一半,請找出這個數字。
例如:輸入如下所示的一個長度為9的數組{1,2,3,2,2,2,5,4,2}。由於數字2在數組中出現了5次,超過數組長度的一半,因此輸出2。如果不存在則輸出0。
解題思路:
本題有以下三種方法可解:
方法一:首先對數組進行排序,在一個有序數組中,次數超過一半的必定是中位數,那么可以直接取出中位數,然后遍歷數組,看中位數是否出現次數超過一半,這取決於排序的時間復雜度,最快為O(nlogn)。
方法二:遍歷數組,用 HashMap 保存每個數出現的次數,這樣可以從map中直接判斷是否有超過一半的數字,這種算法的時間復雜度為O(n),但是這個性能提升是用O(n)的空間復雜度換來的。
方法三(最優解法):根據數組特點得到時間復雜度為O(n)的算法。根據數組特點,數組中有一個數字出現的次數超過數組長度的一半,也就是說它出現的次數比其他所有數字出現的次數之和還要多。因此,我們可以在遍歷數組的時候設置兩個值:一個是數組中的數result,另一個是出現次數times。當遍歷到下一個數字的時候,如果與result相同,則次數加1,不同則次數減一,當次數變為0的時候說明該數字不可能為多數元素,將result設置為下一個數字,次數設為1。這樣,當遍歷結束后,最后一次設置的result的值可能就是符合要求的值(如果有數字出現次數超過一半,則必為該元素,否則不存在),因此,判斷該元素出現次數是否超過一半即可驗證應該返回該元素還是返回0。這種思路是對數組進行了兩次遍歷,復雜度為O(n)。
編程實現(Java):
//思路2:用hashmap保存每個數出現的次數
public int MoreThanHalfNum_Solution(int [] array) {
if(array==null)
return 0;
Map<Integer,Integer> res=new HashMap<>();
int len = array.length;
for(int i=0;i<array.length;i++){
res.put(array[i],res.getOrDefault(array[i],0)+1);
if(res.get(array[i])>len/2)
return array[i];
}
return 0;
}
//思路3:根據數組特點得到時間復雜度為O(n)的算法
public int MoreThanHalfNum_Solution(int [] array) {
if(array==null||array.length==0)
return 0;
int len = array.length;
int result=array[0];
int times=1;
for(int i=1;i<len;i++){
if(times==0){
result=array[i];
times=1;
continue;
}
if(array[i]==result)
times++;
else
times--;
}
//檢查是否符合
times=0;
for(int i=0;i<len;i++){
if(array[i]==result)
times++;
if(times>len/2)
return result;
}
return 0;
}
