前言
题目描述
数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。
例如输入一个长度为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]. 摩尔投票