前言
題目描述
數組中有一個數字出現的次數超過數組長度的一半,請找出這個數字。
例如輸入一個長度爲9的數組{1,2,3,2,2,2,5,4,2}。由於數字2在數組中出現了5次,超過數組長度的一半,因此輸出2。如果不存在則輸出0。
測試數據組:
Case1: {1,2,3,2,2,2,5,4,2}
Result: 2
Case2: {1,2,3,2,4,2,5,2,3}
Result: 0
Case3: {}
Result: 0
Case 4:{1}
Result: 1
Case 5:{1,2}
Result: 0
解法與思路
-
IDEAL 1 排序再查中間值
先進行簡單快速排序. 隨後找到中間值. 再進行一輪的Check. 判斷其Count數是否大於length/2
.
優化點:length>>1
. 使用移位運算. 移位置運算需要注意+0
和-0
的情況. -
IDEAL 2 使用HashMap作爲輔助空間
將數字作爲key
, 個數作爲value
. 存儲進入HashMap. 值得注意的是, 不需要使用TreeMap. 因爲使用TreeMap你也無法獲取有序的序列. 因爲其根據key
進行排序的. -
IDEAL 3 摩爾投票
使用其方法需要注意的是.最後結束的時候還是需要進行判斷一下.
市面上的題解沒有Case3
. 使用Case 3
, 會發現最後計算出爲3. 其非中值. 是錯誤實例.
相關代碼
package com.yanxml.algorithm.offer2.array;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import org.junit.Assert;
import org.junit.Test;
/**
* 題目描述
數組中有一個數字出現的次數超過數組長度的一半,請找出這個數字。
例如輸入一個長度爲9的數組{1,2,3,2,2,2,5,4,2}。由於數字2在數組中出現了5次,超過數組長度的一半,因此輸出2。如果不存在則輸出0。
* */
public class MoreThanHalfOfArray {
// 方法1 - 快排.
public int moreThanHalfNum_Solution(int [] array) {
int result = 0;
if(null != array) {
if(array.length==1) {result=array[0];}
if(array.length==2) {result=(array[0]==array[1]?array[0]:0);}
else if(array.length>2) {
int halfIndex = array.length>>1;
int start=0;
int end = array.length-1;
int index = quickSortPartition(array,start,end);
while(index != halfIndex) {
if(index>halfIndex) {
end = index-1;
index = quickSortPartition(array, start, end);
}else {
start = index+1;
index = quickSortPartition(array, start, end);
}
SortUtil.printArray(array);
}
// 判斷index位置是否是中值位置.
if(checkIndexHalfOrNot(array,array[index])) {
result = array[halfIndex];
}
}
SortUtil.printArray(array);
}
return result;
}
public boolean checkIndexHalfOrNot(int[] array,int indexNum) {
if(null!=array) {
int count = 0;
for(int i=0;i<array.length;i++) {
if(array[i]==indexNum) {
count++;
}
}
if(count>array.length>>1) {
return true;
}
}
return false;
}
public int quickSortPartition(int array[],int begin,int end) {
if(end<begin) {return -1;}
if(end==begin) {return begin;}
int frontIndex = begin;
int endIndex = end;
// 進行一輪快排序
while(frontIndex<endIndex) {
int guard = array[begin]; frontIndex++;
while(array[endIndex]>=guard&& frontIndex<endIndex) {
endIndex--;
}
while(array[frontIndex]<guard && frontIndex<endIndex) {
frontIndex++;
}
SortUtil.swapAAndB(array,frontIndex,endIndex);
}
SortUtil.swapAAndB(array, begin, frontIndex);
return frontIndex;
}
// 方法2-HashMap
public int moreThanHalfNum_Solution_2(int [] array) {
int result = 0;
if(null !=array && array.length>0) {
// 寫入TreeMap
Map<Integer,Integer> map = new HashMap<Integer, Integer>();
for(int i=0;i<array.length;i++) {
if(null != map.get(array[i])) {
map.put(array[i], map.get(array[i])+1);
}else {
map.put(array[i], 1);
}
}
// getFirst 判斷
for(Entry<Integer, Integer> entry:map.entrySet()) {
if(entry.getValue() >= ((array.length+1)/2)) {
result = entry.getKey();
break;
}
}
}
return result;
}
// 方法3 - 使用臨時空間k
public int moreThanHalfNum_Solution_3(int [] array) {
int result =0;
if(null != array && array.length>0) {
int key=array[0];
int value=1;
for(int i=1;i<array.length;i++) {
if(value==0) {
key=array[i];
value =1;
}else {
if(array[i]==key) {
value++;
}else {
value--;
}
}
}
// 判斷範圍值.
if(checkIndexHalfOrNot(array,key)) {
result = key;
}
// 錯誤做法.
// if(value>0) {
// result = key;
// }
}
return result;
}
//@Test
public void testCase1(){
int []array={1,2,3,2,2,2,5,4,2};
int result = new MoreThanHalfOfArray().moreThanHalfNum_Solution(array);
//int result = new MoreThanHalfOfArray().moreThanHalfNum_Solution_2(array);
//int result = new MoreThanHalfOfArray().moreThanHalfNum_Solution_3(array);
Assert.assertEquals(result, 2);
}
// @Test
public void testCase3() {
int []array= {1,2,3,2,4,2,5,2,3};
int result1 = new MoreThanHalfOfArray().moreThanHalfNum_Solution_2(array);
Assert.assertEquals(result1, 0);
int result2 = new MoreThanHalfOfArray().moreThanHalfNum_Solution_2(array);
Assert.assertEquals(result2, 0);
int result3 = new MoreThanHalfOfArray().moreThanHalfNum_Solution_3(array);
Assert.assertEquals(result3, 0);
}
@Test
public void testMoveNumber() {
int i=1;
System.out.println(i>>1);
}
}
Reference
[1]. LetCode 解析
[2]. 摩爾投票