简单来说就是求一个数组中出现次数超过一半的次数的数(保证存在),最容易想到的就是先排序,再返回中间位置的值。
优化方式就是每次删去两个不相等的数,最后找不到不相等的数,那么最后剩下的数就是这个出现次数超过一半的数。
考虑到每次寻找两个不相等的数比较困难,我们可以借助种思想换种写法。
用candidate代表当前候选的数,time次数,从头往后遍历,如果出现一次就time+1,不相等就time-1如果time=0就更新为当前的数。
import java.util.Scanner;
public class 寻找发帖水王 {
public static int Find(int a[],int n){
int answer=a[0];
int number=1;
for (int i=0;i<n;i++){
if (number==0){//如果前面都不对,更新为最新数字
answer=a[i];
number=1;
}else
if (a[i]==answer){//如果相等
number++;
}else{//如果不相等
number--;
}
}
return answer;
}
public static void main(String[] args) {
Scanner cin=new Scanner(System.in);
int n=cin. nextInt();//数量
int a[]=new int[n];
for (int i=0;i<n;i++)
a[i]=cin.nextInt();
System.out.println(Find(a,n));
cin.close();
}
}
扩展题目,有3个水王,其每一个发帖数目超过1/4,求这三个数.发帖超过1/4意味着什么,意味着剩下的帖子不足1/4。也就是将candidate换成数组。
这边要注意写法,可以自己手工模拟流程,可以得到一下正确流程:
1,先找candidate数组中有没有符合的,有则将相应的time数组值+1
2,如果都没有符合的,那么查找candidate数组中有没有为空的,有则将candidate置为该数,同时time数组值置为1
3,如果都没有为空的,那么将所有time数组个数-1
import java.util.Scanner;
public class 寻找发帖水王 {
public static int Find(int a[],int n){
int answer=a[0];
int number=1;
for (int i=0;i<n;i++){
if (number==0){//如果前面都不对,更新为最新数字
answer=a[i];
number=1;
}else
if (a[i]==answer){//如果相等
number++;
}else{//如果不相等
number--;
}
}
return answer;
}
public static void main(String[] args) {
Scanner cin=new Scanner(System.in);
int n=cin. nextInt();//数量
int a[]=new int[n];
for (int i=0;i<n;i++)
a[i]=cin.nextInt();
System.out.println(Find(a,n));
cin.close();
}
}
该种问题还可以在编程之美上扩展,如果存在n个数,其中有n-1个数发帖数量超过1/n,那么可以采用类似做法。创建candidate数组大小为n-1,time数组大小为n-1,同样采用上面三步。
import java.util.Scanner;
public class 寻找发帖水王 {
public static int Find(int a[],int n){
int answer=a[0];
int number=1;
for (int i=0;i<n;i++){
if (number==0){//如果前面都不对,更新为最新数字
answer=a[i];
number=1;
}else
if (a[i]==answer){//如果相等
number++;
}else{//如果不相等
number--;
}
}
return answer;
}
public static void main(String[] args) {
Scanner cin=new Scanner(System.in);
int n=cin. nextInt();//数量
int a[]=new int[n];
for (int i=0;i<n;i++)
a[i]=cin.nextInt();
System.out.println(Find(a,n));
cin.close();
}
}