数组中一个数字出现的次数超过了数组长度的一半,找出这个数字
问题:数组中一个数字出现的次数超过了数组长度的一半,找出这个数字。
我这里给出的是只考虑了正常情况的算法,没有考虑数组无效,以及不符合次数超过数组长度一半的情况。
思路:
(1)将数组排序(排序的原因是为了下面方便统计出次数)
(2)排好序后,分别统计每个元素出现的次数,并对应记录相应的元素。
(3)找出次数最多的元素。
(补充,其实排好序后不需要统计次数了,应为这个数字出现的次数超过了数组长度的一半,那么中间的元素必定是它,所以2,3步多于)
算法:
//这是将数组A排序,为了简单考虑,先用插入排序做实验,为了提高性能可以选择合并排序,堆排序或者快速排序 public static void sort(int[] a) { for(int i = 1; i < a.length; i++) { int key = a[i]; int j = i - 1; while(j >= 0 && a[j]> key) { a[j+1] = a[j]; j--; } a[j+1] = key; } } //统计次数,并找出元素 public static int find(int[] a) { sort(a); int m = a.length / 2 + 1; //由于有一个数字出现的次数超过了数组长度的一般,我用来统计每个数字出现次数的数组长度至多和m一样大。可能用不了这么大,但是不影响我统计。 int[] b = new int[m]; //存放排好序的元素出现的次数 for(int i = 0; i < m; i++) b[i] = 1; //首先假定每个元素至少出现一次。 int[] c = new int[m]; //c[i]表示排好序的每个元素是什么(无重复),对应出现次数在b[i]中,也就是b[i]表示了c[i]这个元素出现的次数。 int i,j = 0, k = 0; //j表示c数组和b数组的下标,k用来维护k左边的元素都是相同的,从k开始就不同于k-1这个元素。 for(i = 1; i < a.length; i++) { if(a[i] == a[i-1]) b[j]++; else { k = i; c[j] = a[k-1]; j++; } } //找出b中最大的元素,就是出现次数最多的下标j,对应的c[j]就是出现次数最多 int max = 0; for(int p = 1; p < b.length; p++) { if(b[p] > b[max]) max = p; } return c[max]; }
心得:我想,大家一看到这个问题基本都是和我想的差不多,如果从效率方面,上面的算法不是一个好的算法。这个问题还有别的方法,可以充分利用次数超过一半这个条件。感兴趣的同学可以讨论回复。后继我会给出更快的算法。
思路2:
为了省去排序的时间,我们完全可以利用java集合类库或者C++标准模板库来统计次数和对应的元素。这里给出用java.HashMap写的算法。
public static int find(int[] a) { HashMap<Integer,Integer> h = new HashMap<Integer,Integer>();//建立一个HashMap,key用来表示数组中出现的元素,value表示其出现的次数。 Set<Integer> kk = h.keySet(); //首先建立一个key视图,如果key视图中有此元素,将其value+1,没有则加入,并将其值设为1。 //有同学会考虑你这kk一开始没有值,之后是h发生了变化,而不是kk发生了变化,这样可以吗?我写了一个输出语句验证了得到的kk是同步的。 for(int i = 0; i < a.length; i++) { System.out.println(kk);//验证得到的kk是同步的。 if(kk.contains(a[i])) { int j = h.get(a[i]); j = j + 1; h.put(a[i], j); } else { h.put(a[i], 1); } } //遍历这个HashMap集,找出最大value对应的key就行。 int maxKey = 0, maxValue = 0; for(Map.Entry<Integer, Integer> entry : h.entrySet()) { int key = entry.getKey(); int value = entry.getValue(); if(value > maxValue) { maxValue = value; maxKey = key; } } return maxKey; }
心得:因为我接触实际项目不是很多,所以有的时候不会想到去用java集合类库,只是从数组去考虑,如果题目没有明确要求我们完全可以利用已有的工具。
思路3:
利用题目给出的条件。希望大家可以讨论讨论,过两天给给出答案。
考虑条件,如果每次都删除两个不同的ID,则剩下的肯定是它:
public static int find(int[] a) { int ID = a[0];//这个是假设中的ID int count = 0;//用来统计ID的次数,如果相同就+1,如果不同就-1, for(int i = 0; i < a.length; i++) { if(count == 0)//说明抵消 { ID = a[i]; count++; } else if(ID == a[i])//相同就增加 count++; else//不同就相减 count--; } return ID; }
声明:该文观点仅代表作者本人,牛骨文系教育信息发布平台,牛骨文仅提供信息存储空间服务。