【鹅厂面试题】——-关于微信红包取中间值(笔试题)
2017-02-06 23:51
176 查看
春节期间小明使用微信收到很多个红包,非常开心。在查看领取红包记录时发现,某个红包金额出现的次数超过了红包总数的一半。请帮小明找到该红包金额。写出具体算法思路和代码实现,要求算法尽可能高效。
给定一个红包的金额数组gifts及它的大小n,请返回所求红包的金额。
若没有金额超过总数的一半,返回0。
测试样例:
[1,2,3,2,2],5
返回:2
其实就是求超过数组一半的元素问题,剑指offer上有。
方法一:利用partition方法
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
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
基于数组的partition方法是成熟的用来求第k位数的方法,在此处我们用来求的是中位数。我们求得中位数,然后判断中位数是否超过数组的一半就得出答案了。
如果求第k个数,while循环条件改为index< k-1(或Index != k-1)即可。
对于每次partition得出的index,如果index>middle,说明中位数在index左边(当前index所对的元素肯定大于中位数)。否则,中位数在index右边。当index=middle时,成功求得中位数,会跳出循环。
这个方法的时间复杂度是O(N)。
另外,千万注意partition中是start,不是0。
方法二:攻守阵地法
我们把第一个元素作为士兵,并使用一个计数变量times。遍历数组,如果出现相同元素,times++。如果出现不同元素,times–。当times减为0时,该士兵死亡。使用新的gifts[i]作为士兵,继续攻守。最后留在战场上的士兵有可能就是超过一半的数字。
最后利用check函数判断即可。
代码如下:
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
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
该方法时间复杂度同样是O(N)。
给定一个红包的金额数组gifts及它的大小n,请返回所求红包的金额。
若没有金额超过总数的一半,返回0。
测试样例:
[1,2,3,2,2],5
返回:2
其实就是求超过数组一半的元素问题,剑指offer上有。
方法一:利用partition方法
class Gift { public: int getValue(vector<int> gifts, int n) { if(n <= 0) return -1; int start = 0; int end = n - 1; int middle = (end - start) >> 1; int index = -1; index = partition(gifts, start, end); while(index < middle){ if(index > middle){ //index>middle,说明中位数在左边,我们需要左调整end end = index - 1; index = partition(gifts, start, end); } else{ //index <= middle,说明中位数在右边,需要右调整start start = index + 1; index = partition(gifts, start, end); } } return check_more_than_half(gifts, n, gifts[middle]); } int partition(vector<int> gifts, int start, int end){ int small = start - 1; //在这行和下面这行,我想把我自己叫哥了,经常由于写代码写的快把start写成0,因为这个耽搁时间我真是醉了... for(int index=start; index<end; ++index){ if(gifts[index] < gifts[end]){ ++small; if(index != small) std::swap(gifts[index], gifts[small]); } } ++small; std::swap(gifts[small], gifts[end]); return small; } int check_more_than_half(vector<int>& gifts, const int n, int val){ int cnt = 0; for(auto i : gifts){ if(i == val) ++cnt; } return (cnt != 0 && cnt > (n >> 1)) ? val : 0; } };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
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
基于数组的partition方法是成熟的用来求第k位数的方法,在此处我们用来求的是中位数。我们求得中位数,然后判断中位数是否超过数组的一半就得出答案了。
如果求第k个数,while循环条件改为index< k-1(或Index != k-1)即可。
对于每次partition得出的index,如果index>middle,说明中位数在index左边(当前index所对的元素肯定大于中位数)。否则,中位数在index右边。当index=middle时,成功求得中位数,会跳出循环。
这个方法的时间复杂度是O(N)。
另外,千万注意partition中是start,不是0。
方法二:攻守阵地法
我们把第一个元素作为士兵,并使用一个计数变量times。遍历数组,如果出现相同元素,times++。如果出现不同元素,times–。当times减为0时,该士兵死亡。使用新的gifts[i]作为士兵,继续攻守。最后留在战场上的士兵有可能就是超过一半的数字。
最后利用check函数判断即可。
代码如下:
class Gift { public: int getValue(vector<int> gifts, int n) { if(n <= 0) return -1; int times = 1; int soldier = gifts[0]; for(int i=1; i<n; ++i){ if(soldier == gifts[i]) ++times; else if(soldier != gifts[i]){ if(--times == 0){ soldier = gifts[i]; times = 1; } } } return check_more_than_half(gifts, n, soldier); } int check_more_than_half(vector<int>& gifts, const int n, const int val){ int cnt = 0; for(auto i : gifts){ if(i == val) ++cnt; } return (cnt != 0 && cnt > (n >> 1)) ? val : 0; } };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
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
该方法时间复杂度同样是O(N)。
相关文章推荐
- 笔试面试题16--微信红包
- 关于sizeof的笔试面试题详解
- 2016年腾讯模拟笔试“微信红包”问题
- 腾讯2016笔试题-微信红包-找出数组中过半数的数字
- 关于链表的一些笔试面试题
- 算法与数据结构——算法题 21:微信红包(2016腾讯校招笔试题) ? 待解决
- 关于"字符串"的笔试,面试题
- 关于微信红包简单算法 PHP Edition
- 名企笔试:腾讯2016招聘笔试(微信红包)
- 腾讯2016笔试题-微信红包-找出数组中过半数的数字
- 笔试题——微信红包
- 关于Android的面试题(笔试题)---选择(个人分析)
- 腾讯笔试题--微信红包
- 腾讯2016笔试题-微信红包-找出数组中过半数的数字
- 关于sizeof的笔试面试题具体解释
- 找链表的中间结点和倒数第k个结点(链表笔试题面试题)
- 关于微信手气红包算法的探讨
- 2016年模拟笔试题--微信红包问题
- 微信红包(2016腾讯校招笔试题)
- 微信红包问题:找出某个出现次数超过红包总数一半的红包的金额(面试题)