题目:数组中有一个数字出现的次数超过了数组长度的一半,找出这个数字。
思路:解法一、排序完后返回arr[N/2] O(nlgn) Arrays.sort(arr); System.out.println(arr[N/2]);
解法二、hash统计
解法三、顺序统计,就跟寻找乱序数组中第K大的数解法一样。O(N),那么这里就是求乱序数组中第N/2大的数,限制:需要改动数组的内容
解法四、不同的数,进行消除
代码:
public class MoreThanHalf {
public static void main(String[] args) {
f(new int[]{5,6,6,6,2,3,6});
}
// 不同的数,进行消除,O(N)
public static void f(int arr[]){
//候选数 先定位第一个元素
int candidate = arr[0];
// 出现的次数
int nTimes = 1;
// 扫描数组
for (int i = 1; i < arr.length; i++) {
// 两两消减为0,应该把现在的元素作为候选值
if (nTimes==0 ) {
candidate = arr[i];
nTimes = 1;
continue;
}
// 如果遇到和候选值相同的,次数加一
if (arr[i]==candidate) {
nTimes++;
// 不同的数,进行消减
}else {
nTimes--;
}
}
//System.out.println(nTimes);
if (nTimes==0) {
System.out.println(-1);
}else {
System.out.println(candidate);
}
}
}
结果:
趣味拓展:加强版水王问题,假如出现的次数恰好为个数的一般,求出这个数。
思路:有个巧妙的方法扫描一遍数组就解决问题,水王发的贴子占总数的一半,说明总数为偶数;不失一般性,假设隔一个数就是水王的id,两两不同最后一定会消减为0,如果水王是最后一个元素,那么每次扫描的时候,多一个动作,和最后一个元素做比较,单独计数,计数恰好一半。如果不是,那么去掉最后一个元素,水王就是留下的那么candidate。
代码:
public class MoreThanHalf {
public static void main(String[] args) {
//进行测试数据要满足测试条件 不然结果会错误
f(new int[]{6,6,6,5,6,1,2,3,4,6});
}
// 不同的数,进行消除,O(N)
public static void f(int arr[]){
//候选数 先定位第一个元素
int candidate = arr[0];
// 出现的次数
int nTimes = 1;
int countOfLast = 1; // 统计这个元素出现的次数
// 扫描数组
for (int i = 1; i < arr.length; i++) {
if (arr[i-1]==arr[arr.length-1]) {
countOfLast++;
}
// 两两消减为0,应该把现在的元素作为候选值
if (nTimes==0 ) {
candidate = arr[i];
nTimes = 1;
continue;
}
// 如果遇到和候选值相同的,次数加一
if (arr[i]==candidate) {
nTimes++;
// 不同的数,进行消减
}else {
nTimes--;
}
}
//System.out.println(nTimes);
if (countOfLast==arr.length/2) {
System.out.println(arr[arr.length-1]);
}else {
System.out.println(candidate);
}
}
}
结果: