《剑指offer》刷题——【时间效率】面试题39:数组中出现次数超过一半的数字(java实现)
一、题目描述
数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。例如输入一个长度为9的数组
{1,2,3,2,2,2,5,4,2}。由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2。如果不
存在则输出0。
二、题目分析
方法一:O(nlogn)
方法二:基于Partition函数的时间复杂度为O(n)–会修改数组
- 把数组排序,排序后位于数组中间的数字一定是那个出现次数超过一半的数字,即将问题转化为数组中第n/2大的数字
- 受快排的启发,O(n)得到数组中第k大的数字
- 先在数组中随机选择一个数字,然后调整数字的顺序,使得比选中的数字小的数字都排在它的左边,比选中的数字大的数字都排在它的右边
- 如果选中的数字的下标刚好是 n/2,那么这个数字就是数组的中位数
- 如果选中的数字的下标大于 n/2,那么中位数应该位于它的左边,接着在它的左边部分的数组中查找
- 如果选中的数字的下标小于n/2,那么中位数应该位于它的右边,接着在它的右边部分的数组中查找
public class Solution {
boolean inputInvalid = false;
public int MoreThanHalfNum_Solution(int [] array) {
if(CheckInvalidArray(array)){
return 0;
}
int mid = array.length >> 1;
int start = 0;
int end = array.length-1;
int index = Partition(array, start, end);
while(index != mid){
if(index > mid){
end = index-1;
index = Partition(array, start,end);
}
else{
start = index +1;
index = Partition(array,start, end);
}
}
int result = array[mid];
if(!CheckMoreThanHalf(array, result)){
result = 0;
}
return result;
}
public boolean CheckInvalidArray(int[] array){
inputInvalid = false;
if(array==null || array.length<=0){
inputInvalid = true;
}
return inputInvalid;
}
public boolean CheckMoreThanHalf(int[] array, int number){
int times = 0;
boolean isMoreThanHalf = true;
for(int i=0; i<array.length;i++){
if(array[i]==number){
times++;
}
}
if(times*2<=array.length){
inputInvalid = true;
isMoreThanHalf = false;
}
return isMoreThanHalf;
}
public int Partition(int[] array, int start, int end){
if(array==null || array.length<=0 || start<0 || end>=array.length){
return -1;
}
int pivotIndex = start;
swap(array, start, end);
int small = start-1;
for(pivotIndex=start; pivotIndex<end; pivotIndex++){
if(array[pivotIndex] < array[end]){
small++;
if(small != pivotIndex){
swap(array, pivotIndex, small);
}
}
}
small++;
swap(array, small, end);
return small;
}
public void swap(int[] array, int pivotIndex, int curIndex){
if(pivotIndex!=curIndex){
int temp = array[pivotIndex];
array[pivotIndex] = array[curIndex];
array[curIndex] = temp;
}
}
}
方法三:根据数组的特点时间复杂度为O(n)–不会修改输入的数组
- 数组中有一个数字出现的次数超过数组长度的一半,即就是它出现的次数比其他所有数字出现次数的和还要多
- 遍历数组保存两个值:1)数组中的一个数字;2)次数
- 遍历数组:
- 若次数为0,保存下一个数字,并把次数设为1;
- 若下一个数字和之前保存的数字相同,则次数加1;
- 若下一个数字和之前保存的数字不同,则次数减一;
- 最后一次把次数设为1时对应的数字,即为所求
public class Solution {
boolean inputInvalid = false;
public int MoreThanHalfNum_Solution(int [] array) {
if(CheckInvalidArray(array)){
return 0;
}
int result = array[0];
int times = 1;
for(int i=1; i<array.length; i++){
if(times==0){
result = array[i];
times =1;
}
else if(array[i]==result){
times++;
}
else{
times--;
}
}
if(!CheckMoreThanHalf(array,result)){
result =0;
}
return result;
}
public boolean CheckInvalidArray(int[] array){
inputInvalid = false;
if(array==null || array.length<=0){
inputInvalid = true;
}
return inputInvalid;
}
public boolean CheckMoreThanHalf(int[] array, int number){
int times = 0;
boolean isMoreThanHalf = true;
for(int i=0; i<array.length;i++){
if(array[i]==number){
times++;
}
}
if(times*2<=array.length){
inputInvalid = true;
isMoreThanHalf = false;
}
return isMoreThanHalf;
}
}