数组中一个数字出现的次数超过了数组长度的一半,找出这个数字

 

问题:数组中一个数字出现的次数超过了数组长度的一半,找出这个数字。

我这里给出的是只考虑了正常情况的算法,没有考虑数组无效,以及不符合次数超过数组长度一半的情况。

思路:

(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;
	}


  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值