47. 数组中出现次数超过一半的数字[Number appears more than half times]

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

例如长度为9的数组{1,2,3,2,2,2,5,4,2}中次数超过了数组长度的一半的数字为2,而长度为8的数组{1,2,3,2,2,2,5,4}则为非法输入。

思路一】:先对数组进行排序,再遍历排序后的数组,统计每个数的次数,出现次数最大的数即为要找的数。

时间复杂度:O(nlgn)+ O(n)= O(nlgn);空间复杂度:O(1)。

思路二】:先对数组进行排序,出现次数超过数组长度的一半的数必然是数组中间的那个数。

时间复杂度:O(nlgn)+ O(1)= O(nlgn);空间复杂度:O(1)。

思路三】:使用Hash表。遍历数组中的每个数字,找到它在哈希表中对应的位置并增加它出现的次数。Hash表只适用于元素的范围(range)比较小的情况,而假设我们的数组是一个整型数组,取值范围跨度太大,所以不适合用哈希表,太浪费空间了。

时间复杂度:O(n);空间复杂度:O(range)。

思路四】:既然该数字为数组的中位数,即长度为n的数组中第[n/2]大数字。那么有没有更快的方法求解?我们已经有成熟的O(n)算法求解数组的第K大数字,即Kmin。那么可以借鉴其思想。

时间复杂度:O(n);空间复杂度:O(1)。

缺点是由于使用了QuickSort的Partition算法,需要交换数组中数字顺序,会修改输入数组。

具体代码如下:

 C++ Code 
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
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
 
// 47_NumberAppearMoreThanHalf.cpp : Defines the entry point for the console application.
//

#include   "stdafx.h"
#include  <iostream>
using   namespace  std;

bool  g_bValid =  true ;

// swap a and b
void  myswap( int  &a,  int  &b)
{
    
int  t = a;
    a = b;
    b = t;
}

// use Partition of QuickSort to get Kmin
int  Partition( int  a[],  int  left,  int  right) 
{
// partition so that a[left..p-1]<a[p] and a[p+1..right]>=a[p]
     int  pivot = a[left], i = left , j = right;
    
while  (i < j) 
    { 
//  i from left, j from right
         while  (a[i] <= pivot ) i++;
        
while  (a[j] > pivot ) j--;
        
if  (i < j) 
            myswap(a[i],a[j]);
    }
    myswap(a[left],a[j]);
    
return  j;
}

// check whether array is valid
bool  IsArrayValid( int  a[], int  n)
{
    g_bValid = 
true ;
    
if ( NULL ==a||n<= 0 )
    {
        g_bValid = 
false ;
    }
    
return  g_bValid;
}

// check whether result appears more than half
bool  IsAppearMoreThanHalf( int  a[], int  n, int  result)
{
    
int  times =  0 ;
    
for  ( int  i= 0 ;i<n;++i)
        
if  (a[i]==result)
            times++;

    
bool  bIsMoreThanHalf =  true ;
    
if  ( 2 *times<=n)
    {
        g_bValid = 
false ;
        bIsMoreThanHalf = 
false ;
    }

    
return  bIsMoreThanHalf;
}

// get number which appears more than half of array
int  NumberAppearMoreThanHalf_Solution1( int  a[], int  n)
{
// O(n)
     // whether array is valid
     if  (!IsArrayValid(a,n))
        
return   0 ;

    
int  left =  0 ;
    
int  right = n- 1 ;
    
int  middle = n/ 2 ;
    
int  pivot = Partition(a,left,right);
    
while (pivot!=middle)
    {
        
if  (pivot<middle)
        {
            left = pivot+
1 ;
            pivot =Partition(a,left,right);
        }
        
else
        {
            right = pivot-
1 ;
            pivot =Partition(a,left,right);
        }
    }
    
// pivot == middle
     int  result = a[middle];

    
// check whether result appears more than half
     if  (!IsAppearMoreThanHalf(a,n,result))
        
return   0 ;

    
return  result;
}

// get number which appears more than half of array
int  NumberAppearMoreThanHalf_Solution2( int  a[], int  n)
{
// O(n)
     // whether array is valid
     if  (!IsArrayValid(a,n))
        
return   0 ;

    
int  result = a[ 0 ];
    
int  appearTimes =  1 ;
    
for  ( int  i= 1 ;i<n;++i)
    {
        
if  (a[i]==result)
            appearTimes++;
        
else
            appearTimes--;

        
if  (appearTimes== 0 )
        {
            result = a[i];
            appearTimes = 
1 ;
        }
    }

    
// check whether result appears more than half
     if  (!IsAppearMoreThanHalf(a,n,result))
        
return   0 ;

    
return  result;
}

void  test_base( int  a[], int  n)
{
    
int  result = NumberAppearMoreThanHalf_Solution2(a,n);
    
if  (g_bValid)
        cout<<result<<endl;
    
else
        cout<<
"Invalid array." <<endl;
}

void  test_case1()
{
    
int  a[] = { 1 , 2 , 3 , 2 , 2 , 2 , 5 , 4 , 2 };
    
int  n =  sizeof (a)/ sizeof ( int );
    test_base(a,n); 
// 2
}

void  test_case2()
{
    
int  a[] = { 1 , 2 , 3 , 2 , 2 , 2 , 5 , 4 };
    
int  n =  sizeof (a)/ sizeof ( int );
    test_base(a,n); 
// invalid array
}

void  test_main()
{
    test_case1();
    test_case2();
}

int  _tmain( int  argc, _TCHAR* argv[])
{
    test_main();
    
return   0 ;
}

 思路五】:数组中有个数字出现的次数超过了数组长度的一半。也就是说,有个数字出现的次数比其他所有数字出现次数的和还要多。因此我们可以考虑在遍历数组的时候保存两个值:一个是数组中的一个数字,一个是其对应的出现次数。当我们遍历到下一个数字的时候,如果下一个数字和我们之前保存的数字相同,则次数加1。如果下一个数字和我们之前保存的数字不同,则次数减1。如果次数为零,我们需要保存下一个数字,并把次数设为1。这样最后剩下的数字肯定就是出现次数超过数组长度一半的数字。

时间复杂度:O(n);空间复杂度:O(1)。

相比【思路四】不会修改输入数组。

具体代码如下:

 C++ Code 
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
 
// get number which appears more than half of array
int  NumberAppearMoreThanHalf_Solution2( int  a[], int  n)
{
// O(n)
     // whether array is valid
     if  (!IsArrayValid(a,n))
        
return   0 ;

    
int  result = a[ 0 ];
    
int  appearTimes =  1 ;
    
for  ( int  i= 1 ;i<n;++i)
    {
        
if  (a[i]==result)
            appearTimes++;
        
else
            appearTimes--;

        
if  (appearTimes== 0 )
        {
            result = a[i];
            appearTimes = 
1 ;
        }
    }

    
// check whether result appears more than half
     if  (!IsAppearMoreThanHalf(a,n,result))
        
return   0 ;

    
return  result;
}

 【参考】

http://zhedahht.blog.163.com/blog/static/25411174201085114733349/

http://www.cnblogs.com/python27/archive/2011/12/15/2289534.html

转载于:https://www.cnblogs.com/hellogiser/p/3744962.html

1、资源项目源码均已通过严格测试验证,保证能够正常运行;、 2项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行;、 2项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值