劍指offer之打印超過數組一半的數字
問題描述
數組中有一個數字出現的次數超過數組長度的一半,請找出這個數字。例如輸入一個長度為9的數組{1,2,3,2,2,2,5,4,2}。由於數字2在數組中出現了5次,超過數組長度的一半,因此輸出2。如果不存在則輸出0。
解題思路
該問題有很多種解法,其中包括了使用HashMap、排序與候選法進行解題。
這裡主要是講解有關於使用候選法來解決這道算法問題。
候選法
一開始,我在看到這個問題的第一反映是通過哈希表來解決這個問題。當我使用了HashMap方法解決了這個問題之後,我覺得這道題應該不是考察使用哈希表來解決的。
所以,我就查看了題解,在官方的題解方法中,看到了候選的方法,具體的候選法的思路如下所示:
- 首先,設置候選者cnt=-1,並且設置候選數為count = 0
- 然後遍歷整個數組。判斷如果候選數0,則將候選者設置為當前數字;如果候選數大於0,則判斷當前值是否與候選數相同,如果相同,則將候選數count++; 如果不相同,則將count–;
- 遍歷完數組後,剩下的cnt為臨時眾數。需要再重新遍歷一次數組,判斷cnt的出現次數是否查過數組長度的一般。
算法的實現過程
使用HashMap方法
因為使用該方法過於簡單,所以我就不再講解這個解題的思路。
public int MoreThanHalfNum_Solution(int [] array) {
if(array == null || array.length == 0) return 0;
int len = array.length;
int mid = len / 2;
// 建立HashMap存儲該數組中的位數,只需要遍歷一次即可
Map<Integer, Integer> map = new HashMap<>();
for(int i=0; i<len; i++){
int m = array[i];
map.put(m, map.getOrDefault(m, 0)+1);
}
for(int key: map.keySet()){
if(map.get(key) > mid) return key;
}
return 0;
}
使用候選法求解
//候選法,如果一個數為眾數,那麼這個數一定比其他的數存在的更多,可以抵消掉其他的數
public int MoreThanHalfNum_Solution(int [] array) {
if(array == null || array.length ==0 ) return 0;
int len = array.length;
int mid = len/2;
int cnt = -1;
int count = 0;
//首先遍曆數組,找出眾數
for(int i=0; i<len; i++){
if(count == 0){
cnt = array[i];
count ++;
}else{
if(cnt == array[i]){
count ++;
}else{
count --;
}
}
}
//獲得到眾數,然後判斷眾數的個數是否大於數組的一半
count = 0;
for(int i=0; i<len; i++){
if(cnt == array[i]) count ++;
}
if(count > mid) return cnt;
else return 0;
}