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

例如长度为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;
    )
    {
        g_bValid = false;
    }
    return g_bValid;
}

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

bool bIsMoreThanHalf = true;
    *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))
        ;

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

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

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))
        ;

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

)
        {
            result = a[i];
            appearTimes = ;
        }
    }

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

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 n = sizeof(a)/sizeof(int);
    test_base(a,n); // 2
}

void test_case2()
{
    };
    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();
    ;
}

思路五】:数组中有个数字出现的次数超过了数组长度的一半。也就是说,有个数字出现的次数比其他所有数字出现次数的和还要多。因此我们可以考虑在遍历数组的时候保存两个值:一个是数组中的一个数字,一个是其对应的出现次数。当我们遍历到下一个数字的时候,如果下一个数字和我们之前保存的数字相同,则次数加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))
        ;

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

)
        {
            result = a[i];
            appearTimes = ;
        }
    }

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

return result;
}

 【参考】

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

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

47. 数组中出现次数超过一半的数字[Number appears more than half times]的更多相关文章

  1. 九度OJ 1370 数组中出现次数超过一半的数字

    题目地址:http://ac.jobdu.com/problem.php?pid=1370 题目描述: 数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字.例如输入一个长度为9的数组{1,2 ...

  2. 数组中出现次数超过一半的数字 -java

    数组中出现次数超过一半的数字 -java 方法一: 数组排序,然后中间值肯定是要查找的值. 排序最小的时间复杂度(快速排序)O(NlogN),加上遍历. 方法二: 使用散列表的方式,也就是统计每个数组 ...

  3. 【C语言】统计数组中出现次数超过一半的数字

    //统计数组中出现次数超过一半的数字 #include <stdio.h> int Find(int *arr, int len) { int num = 0; //当前数字 int ti ...

  4. Leetcode - 剑指offer 面试题29:数组中出现次数超过一半的数字及其变形(腾讯2015秋招 编程题4)

    剑指offer 面试题29:数组中出现次数超过一半的数字 提交网址: http://www.nowcoder.com/practice/e8a1b01a2df14cb2b228b30ee6a92163 ...

  5. 《剑指offer》— JavaScript(28)数组中出现次数超过一半的数字

    数组中出现次数超过一半的数字 题目描述 数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字.例如输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}.由于数字2在数组中出现了5次,超 ...

  6. 《剑指offer》第三十九题(数组中出现次数超过一半的数字)

    // 面试题39:数组中出现次数超过一半的数字 // 题目:数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字.例 // 如输入一个长度为9的数组{1, 2, 3, 2, 2, 2, 5, ...

  7. 剑指Offer - 九度1370 - 数组中出现次数超过一半的数字

    剑指Offer - 九度1370 - 数组中出现次数超过一半的数字2013-11-23 03:55 题目描述: 数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字.例如输入一个长度为9的数组 ...

  8. 剑指Offer:数组中出现次数超过一半的数字【39】

    剑指Offer:数组中出现次数超过一半的数字[39] 题目描述 数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字.例如,输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}.由于这 ...

  9. 编程算法 - 数组中出现次数超过一半的数字 代码(C)

    数组中出现次数超过一半的数字 代码(C) 本文地址: http://blog.csdn.net/caroline_wendy 题目: 数组中有一个数字出现的次数超过数组长度的一半, 请找出这个数字. ...

随机推荐

  1. onethink常用标签的使用示例

    首页文章模型列表输出: <article:list name="article" category="2" row="3" order ...

  2. Java异常分类

    一.基本概念 看java的异常结构图 Throwable是所有异常的根,java.lang.ThrowableError是错误,java.lang.ErrorException是异常,java.lan ...

  3. CSS布局自适应高度解决方法

    这是一个比较典型的三行二列布局,每列高度(事先并不能确定哪列的高度)的相同,是每个设计师追求的目标,按一般的做法,大多采用背景图填充.加JS脚本的方法使列的高度相同,本文要介绍的是采用容器溢出部分隐藏 ...

  4. Cocos2d-X3.0 刨根问底(九)----- 场景切换(TransitionScene)源码分析

    上一章我们分析了Scene与Layer相关类的源码,对Cocos2d-x的场景有了初步了解,这章我们来分析一下场景变换TransitionScene源码. 直接看TransitionScene的定义 ...

  5. 高斯混合聚类及EM实现

    一.引言 我们谈到了用 k-means 进行聚类的方法,这次我们来说一下另一个很流行的算法:Gaussian Mixture Model (GMM).事实上,GMM 和 k-means 很像,不过 G ...

  6. BZOJ4241 历史研究

    Description IOI国历史研究的第一人——JOI教授,最近获得了一份被认为是古代IOI国的住民写下的日记.JOI教授为了通过这份日记来研究古代IOI国的生活,开始着手调查日记中记载的事件. ...

  7. IRP IO_STACK_LOCATION 《寒江独钓》内核学习笔记(1)

    在学习内核过滤驱动的过程中,遇到了大量的涉及IRP操作的代码,这里有必要对IRP的数据结构和与之相关的API函数做一下笔记. 1. 相关阅读资料 <深入解析 windows 操作系统(第4版,中 ...

  8. 初识A*算法

    写这篇文章的初衷是应一个网友的要求,当然我也发现现在有关人工智能的中文站点实在太少,我在这里抛砖引玉,希望大家都来热心的参与. 还是说正题,我先拿A*算法开刀,是因为A*在游戏中有它很典型的用法,是人 ...

  9. MongoDB的安装 转

    第1章 MongoDB的安装 (黎明你好原创作品,转载请注明) 1.1 MongoDB简介 MongoDB是一个基于分布式文件存储的数据库开源项目.由C++语言编写,旨在为WEB应用提供可护展的高性能 ...

  10. Java初学(三)

    一.使用键盘录入数据 三步:1.导入包:import  java.util.Scanner; 2.创建键盘录入对象:Scanner sc=new  Scanner(System.in);   3.通过 ...