博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
数组中出现次数超过一半的数字
阅读量:6717 次
发布时间:2019-06-25

本文共 2068 字,大约阅读时间需要 6 分钟。

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

 

看到这道题,我们马上就会想到,要是这个数组是排序的数组就好了。如果是排序的数组,那么我们只要遍历一次就可以统计出每个数字出现的次数,这样也就能找出符合要求的数字了。题目给出的数组没有说是排好序的,因此我们需要给它排序。排序的时间复杂度是O(nlogn),再加上遍历的时间复杂度O(n),因此总的复杂度是O(nlogn)

接下来我们试着看看能不能想出更快的算法。前面思路的时间主要是花在排序上。我们可以创建一个哈希表来消除排序的时间。哈希表的键值(Key)为数组中的数字,值(Value)为该数字对应的次数。有了这个辅助的哈希表之后,我们只需要遍历数组中的每个数字,找到它在哈希表中对应的位置并增加它出现的次数。这种哈希表的方法在数组的所有数字都在一个比较窄的范围内的时候很有效。就是一个应用哈希表的例子。不过本题并没有限制数组里数字的范围,我们要么需要创建一个很大的哈希表,要么需要设计一个很复杂的方法来计算哈希值。因此总体说来这个方法还不是很好。

前 面两种思路都没有考虑到题目中数组的特性:数组中有个数字出现的次数超过了数组长度的一半。也就是说,有个数字出现的次数比其他所有数字出现次数的和还要 多。

因此我们可以考虑在遍历数组的时候保存两个值:一个是数组中的一个数字,一个是次数。当我们遍历到下一个数字的时候,如果下一个数字和我们之前保存的 数字相同,则次数加1。如果下一个数字和我们之前保存的数字不同,则次数减1。如果次数为零,我们需要保存下一个数字,并把次数设为1。由于我们要找的数字出现的次数比其他所有数字出现的次数之和还要多,那么要找的数字肯定是最后一次把次数设为1时对应的数字

基于这个思路,我们不难写出如下代码:

 

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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
#include<iostream>
using 
namespace 
std;
 
bool 
CheckMoreThanHalf(
int 
*numbers, 
int 
length, 
int 
number);
 
int 
MoreThanHalfNumber(
int 
*numbers, 
int 
length)
{
    
if
(numbers == NULL || length <= 0)
        
return 
-1;
     
    
int 
result = numbers[0];
    
int 
times = 1;
    
for
(
int 
i = 1; i < length; ++i)
    
{
        
if
(times == 0)
        
{
            
result = numbers[i];
            
times = 1;
        
}
        
else 
if
(numbers[i] == result)
            
times++;
        
else
            
times--;
    
}
     
    
if
(!CheckMoreThanHalf(numbers, length, result))
        
result = 0;
     
    
return 
result;
}
 
bool 
CheckMoreThanHalf(
int 
*numbers, 
int 
length, 
int 
number)
{
    
int 
times = 0;
    
for
(
int 
i = 0; i < length; ++i)
    
{
        
if
(numbers[i] == number)
            
times++;
    
}
     
    
bool 
isMoreThanHalf = 
true
;
    
if
(times * 2 <= length)
    
{
        
isMoreThanHalf = 
false
;
    
}
     
    
return 
isMoreThanHalf;
}
 
int 
main()
{
    
int 
numbers[] = {1, 2, 3, 2, 2, 2, 5, 4, 2};
    
int 
length = 
sizeof
(numbers) / 
sizeof
(
int
);
     
    
cout<<MoreThanHalfNumber(numbers, length)<<endl;
     
    
return 
0;
}

 

 

 

 在上述代码中,有两点值得讨论:

(1)      我们需要考虑当输入的数组或者长度无效时,如何告诉函数的调用者输入无效。关于处理无效输入的几种常用方法,在中有详细的讨论;

(2)      本算法的前提是输入的数组中的确包含一个出现次数超过数组长度一半的数字。如果数组中并不包含这么一个数字,那么输入也是无效的。因此在函数结束前我还加了一段代码来验证输入是不是有效的。

 

来源:

 

本文转自夏雪冬日博客园博客,原文链接:http://www.cnblogs.com/heyonggang/p/3631114.html,如需转载请自行联系原作者

你可能感兴趣的文章
day3-Nfs
查看>>
day4-Httpd
查看>>
Linux下STM32工程搭建
查看>>
pstree
查看>>
RHCS多节点部署应用企业环境
查看>>
Apache反向代理Tomcat(mod_proxy方式)
查看>>
安装Gitlab 10.5.2社区版
查看>>
cut命令详解
查看>>
linux知识散记(1)-----64位的系统运行32位程序
查看>>
只有坚持,坚持,在坚持,才能取得最后的成功
查看>>
常用的加密算法--对称加密
查看>>
shell学习之xargs
查看>>
360手机卫士获2011移动互联网最佳应用
查看>>
网络出现故障 托福网考遭遇“卡壳”
查看>>
戴尔携手微软:开发私有云系统
查看>>
S3c2410_SDIO_调试笔记<一>
查看>>
zabbix监控windows tcp连接数
查看>>
Java5线程并发库之其他同步工具类
查看>>
MySQL5.5源码包和5.6源码包安装
查看>>
关于上报错误最简单的实现方式--利用图片
查看>>