如何在O(n)的时间复杂度内找出数组中

方法一:每次取出两个不同的数,剩下的数字中重复出现次数超过一半的数字肯定,将规模缩小化。如果每次删除两个不同的数,这里当然不是真的把它们踢出数组,而是对于候选数来说,出现次数减一,对于其他数来说,循环遍历就行。在剩余的数字里,原最高频数出现的频率一样超过了50%,不断重复这个过程,最后剩下的将全是同样的数字,即最高频数。此算法避免了排序,时间复杂度只有O(n).

程序示例如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#include "stdafx.h"
#include <stdio.h>
 
int  FindMostApperse( int * num,  int  len)
{
     int  candidate = 0;
     int  count = 0;
     for  ( int  i = 0; i < len; i++)
     {       
         if  (count == 0)
         {
             candidate = num[i];
             count = 1;
         }
         else
         {
             if  (candidate == num[i])
                 count++;
             else
                 count--;
         }
         printf ( "num[%d]=%d,count=%d,candidate=%d\n" , i, num[i], count, candidate);
     }
     return  candidate;
}
int  main()
{
     int  arr[] = { 2, 1, 1, 2, 3, 1, 1, 1 };
     int  len =  sizeof (arr) /  sizeof (arr[0]);
     printf ( "%d\n" , FindMostApperse(arr, len));
     getchar ();
     return  0;
}

  效果如图:

方法二:Hash法。首先创建一个hash_map,其中key为数组元素值,value为此数出现的次数。遍历一遍数组,用hash_map统计每个数出现的次数,并用两个值存储目前出现次数最多的数和对应出现的次数,此时的时间复杂度为O(n),空间复杂度为O(n),满足题目的要求。

方法三:原创,用map,不知时间复杂度是否符合要求,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#include "stdafx.h"
#include <iostream>
#include <map>
using  namespace  std;
bool  findOverHalf( int  *a,  int  size,  int  &val)
{
     if  (a == NULL || size <= 0)
         return  false ;
     map< int int > m;
     for  ( int  i=0; i < size; i++)
     {
         m[a[i]]++;
         if  (m[a[i]]>size / 2)
         {
             val = a[i];
             return  true ;
         }
     }
     return  false ;
}
int  main()
{
     int  val = 0;
     int  a[] = { 1, 5, 4, 3, 4, 4, 0, 5, 5, 5, 5 };
     if  (findOverHalf(a, 11, val))
         cout << val << endl;
     else
         cout <<  "无出现次数过半的数"  << endl;
     getchar ();
     return  0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值