题目描述:
数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。 假设数组非空,并且一定存在满足条件的数字。
思考题:假设要求只能使用 O(n) 的时间和额外 O(1) 的空间,该怎么做呢?
样例:
输入:[1,2,1,1,3] 输出:1
分析:
数组中有一个数字出现的次数超过数组长度的一半,如果对这个数组进行排序,那么排序之后位于数组中间的数字一定就是出现次数超过数组长度一半的那个数字。即求长度为n的数组中第n/2大的数字,在时间复杂度为O(n)的情况下。
法1:基于快速排序的思想,确定一个数字,将小于这个数字的数放在左边,大于该数字的数放在数字右边。若最终这个数字的位置等于n/2,即为我们要找的数字;若数字的位置小于n/2,则继续在该位置右侧递归;若数字的位置大于n/2则继续在该位置左侧递归。
public int moreThanHalfNum_Solution(int[] nums) {
if(nums==null||nums.length==0)
return -1;
int mid=nums.length/2;
int left=0,right=nums.length-1;
int index=quickSort(nums,left,right);
while(index!=mid) {
if(index>mid) {
right=index-1;
index=quickSort(nums,left,right);
}else {
left=index+1;
index=quickSort(nums,left,right);
}
}
int re=nums[mid];
int count=0;
for(int i=0;i<nums.length;i++) {
if(nums[i]==re)
count++;
if(count*2>nums.length)
return re;
}
return -1;
}
public int quickSort(int[] num,int left,int right) {
if(left>right)
return -1;
int temp=num[left];
int i=left,j=right;
while(i!=j) {
while(num[j]>=temp&&i<j)
j--;
while(num[i]<=temp&&i<j)
i++;
if(i<j) {
int t=num[i];
num[i]=num[j];
num[j]=t;
}
}
num[left]=num[i];
num[i]=temp;
return i;
}
法2:当一个数字在数组中出现的次数长度超过一半时,那么这个数字的出现次数比其他数字出现次数的总和还要多。因此在遍历数组的时候保存两个数字,一个是出现的次数,一个是数字。当当前遍历的数字等于保存的数字时,次数加1,如果不等则次数减1,当count等于0时,重新从1开始计数,并将保存的数字更新为当前的数字。由于我们要找的数字出现次数之和比其他所有数字的出现次数之和还要多,因此要找的数字肯定是最后一次把count置为0的数字。
public int moreThanHalfNum_Solution(int[] nums) {
if(nums==null||nums.length==0)
return 0;
int count=1,s=nums[0];
for(int i=1;i<nums.length;i++) {
if(nums[i]!=s) {
count--;
if(count==0) {
s=nums[i];
count=1;
}
}else {
count++;
}
}
count=0;
for(int i=0;i<nums.length;i++) {
if(nums[i]==s)
count++;
if(count*2>nums.length)
return s;
}
return 0;
}

博客围绕找出数组中出现次数超过数组长度一半的数字展开。给出样例输入输出,分析部分提出两种解法。一是基于快速排序思想递归查找;二是遍历数组,通过计数更新保存数字,最终找到目标数字,还提及了时间和空间复杂度要求。
1014

被折叠的 条评论
为什么被折叠?



