Redian新闻
>
请教一个查找算法问题
avatar
请教一个查找算法问题# JobHunting - 待字闺中
b*s
1
电面问道,给一个数组n个数字,找出最大的数。然后找出第二大的数。
我当时用了最简单的方式比较2n次。找出2个数。但是面试的说有更好的算法小于2n次
,请问是什么算法啊?谢谢
avatar
l*a
2
找最大的 ,考虑一下淘汰赛,n次比较
然后2nd biggest 在被冠军淘汰的那条path上。。lgn-1

【在 b********s 的大作中提到】
: 电面问道,给一个数组n个数字,找出最大的数。然后找出第二大的数。
: 我当时用了最简单的方式比较2n次。找出2个数。但是面试的说有更好的算法小于2n次
: ,请问是什么算法啊?谢谢

avatar
j*y
3
至少可以优化一下。
假设有 n 个数据, 等分成两部分A, B 每部分有 n / 2个数据
找出 A 中的最大值 A_max 用 (n/2 - 1) 次比较
找出 B中的最大值 B_max 用 (n/2 - 1) 次比较
如果 A_max > B_max 那么, 整个 的最大值是 A_max
下面来找,第二大的值, 这个时候只需 看 (A - {A_max}) Union {B_max}
这 n/2 个数, 找出其中的最大值,就是 整个的第二大的值, 用 (n/2 - 1)次比较。
总共用 3 * (n /2 - 1) 次比较。

【在 b********s 的大作中提到】
: 电面问道,给一个数组n个数字,找出最大的数。然后找出第二大的数。
: 我当时用了最简单的方式比较2n次。找出2个数。但是面试的说有更好的算法小于2n次
: ,请问是什么算法啊?谢谢

avatar
b*s
4
明白了,多谢。

【在 l*****a 的大作中提到】
: 找最大的 ,考虑一下淘汰赛,n次比较
: 然后2nd biggest 在被冠军淘汰的那条path上。。lgn-1

avatar
l*b
5
clrs 9.1-1: n + [log n] - 2次比较,不知道是不是要比交次数最少
avatar
l*a
6
上面有code吗?
不知道这个思路怎么写code

【在 l*******b 的大作中提到】
: clrs 9.1-1: n + [log n] - 2次比较,不知道是不是要比交次数最少
avatar
l*b
7
没code,大约是这样做:
分成n/2对,没一对做比较取较小的一个。这样得到 n/2个数,找到这里面最小的两个
,然后用第二小的与最小的那个成对的数比较可以得到n个数里最小的两个
(3 5) (4 2) (8 7)
---> 3 2 7 最小的两个3 2,用3 和 4比较得知2 , 3是所有里面最小的两个
回想一下感觉和建堆的复杂度类似

【在 l*****a 的大作中提到】
: 上面有code吗?
: 不知道这个思路怎么写code

avatar
M*A
8
int find_max_sec(int *a, int n) {
if(n<2) return 0;
int max, sec_max;
if(a[1]max=a[0];
sec_max=a[1];
}
else {
max=a[1];
sec_max=a[0];
}
for(int i=2;iif(a[i]>max) {
sec_max=max;
max=a[i];
}
if(a[i]sec_max){
sec_max=a[i];
}
}
cout<cout<return 1;
}
avatar
j*y
9
写了一个 code ,不过需要 O((log n)) 的 extra space
first get k = log n;
int * findPath(int A[], int start, int end, int & size)
{
if(start == end)
{
int *result = new int[k];
result[0] = A[start];
size = 1;
return result;
}
int mid = (start + end) / 2;
int size1 = 0, size2 = 0;
int *left = findPath(A, start, mid, size1);
int *right = findPath(A, mid + 1, end, size2);
if(left[0] > right[0])
{
left[size1] = right[0];
size = size1 + 1;
delete right;
return left;
}
else
{
right[size2] = left[0];
size = size2 + 1;
delete left;
return right;
}
}

【在 l*******b 的大作中提到】
: 没code,大约是这样做:
: 分成n/2对,没一对做比较取较小的一个。这样得到 n/2个数,找到这里面最小的两个
: ,然后用第二小的与最小的那个成对的数比较可以得到n个数里最小的两个
: (3 5) (4 2) (8 7)
: ---> 3 2 7 最小的两个3 2,用3 和 4比较得知2 , 3是所有里面最小的两个
: 回想一下感觉和建堆的复杂度类似

avatar
b*s
10
没看懂,还是多谢code了。测试了一下,貌似second max不对。。。不管k换成3还是4
,都给第一个72,第二个是69,第三个是70.
int main()
{
int a[10]={39,31,34,53,24,70,42,69,72,44};
int *p;
int size = 0;
p = findPath(a,0,10,size);
cout<cout<cout<cout<getchar();
return 1;
}

【在 j*****y 的大作中提到】
: 写了一个 code ,不过需要 O((log n)) 的 extra space
: first get k = log n;
: int * findPath(int A[], int start, int end, int & size)
: {
: if(start == end)
: {
: int *result = new int[k];
: result[0] = A[start];
: size = 1;
: return result;

avatar
c*t
11
弱问一句,难道不是遍历一遍就可以找出来两个最大的数吗?

★ 发自iPhone App: ChineseWeb 7.7

【在 b********s 的大作中提到】
: 电面问道,给一个数组n个数字,找出最大的数。然后找出第二大的数。
: 我当时用了最简单的方式比较2n次。找出2个数。但是面试的说有更好的算法小于2n次
: ,请问是什么算法啊?谢谢

avatar
w*g
12
牛!

【在 l*******b 的大作中提到】
: 没code,大约是这样做:
: 分成n/2对,没一对做比较取较小的一个。这样得到 n/2个数,找到这里面最小的两个
: ,然后用第二小的与最小的那个成对的数比较可以得到n个数里最小的两个
: (3 5) (4 2) (8 7)
: ---> 3 2 7 最小的两个3 2,用3 和 4比较得知2 , 3是所有里面最小的两个
: 回想一下感觉和建堆的复杂度类似

avatar
c*t
13
理论上是,但实际上 最普通的走一遍算法平均也是 n+n/2次比较,因为if a[i] >
current max then it doesn't need to compare with the current second max.
best is n, worst is 2n.

【在 j*****y 的大作中提到】
: 至少可以优化一下。
: 假设有 n 个数据, 等分成两部分A, B 每部分有 n / 2个数据
: 找出 A 中的最大值 A_max 用 (n/2 - 1) 次比较
: 找出 B中的最大值 B_max 用 (n/2 - 1) 次比较
: 如果 A_max > B_max 那么, 整个 的最大值是 A_max
: 下面来找,第二大的值, 这个时候只需 看 (A - {A_max}) Union {B_max}
: 这 n/2 个数, 找出其中的最大值,就是 整个的第二大的值, 用 (n/2 - 1)次比较。
: 总共用 3 * (n /2 - 1) 次比较。

avatar
j*y
14
走一遍好像不行吧? 比如 10 9 8 7 6 5 4 3
走一遍可以得到 10 和 9 ?

【在 c********t 的大作中提到】
: 理论上是,但实际上 最普通的走一遍算法平均也是 n+n/2次比较,因为if a[i] >
: current max then it doesn't need to compare with the current second max.
: best is n, worst is 2n.

avatar
p*2
15

其实这题没那么复杂。就是像你说的就可以了。遍历一遍。

【在 c********t 的大作中提到】
: 弱问一句,难道不是遍历一遍就可以找出来两个最大的数吗?
:
: ★ 发自iPhone App: ChineseWeb 7.7

avatar
p*2
16

为什么不能的到?

【在 j*****y 的大作中提到】
: 走一遍好像不行吧? 比如 10 9 8 7 6 5 4 3
: 走一遍可以得到 10 和 9 ?

avatar
p*2
17
arr=[10,9,8,7,6,5,4,3]
first=arr[0..1].max
second=arr[0..1].min
(2...arr.length).each do |i|
if arr[i]>second
if(arr[i]>first)
second=first
first=arr[i]
else
second=arr[i]
end
end
end
p first
p second
avatar
c*t
18
明白了,多谢!
把你说的扩展为n,要开至少n空间,存所有path,(用map好些)divide and conquer,
(如果每次不释放被conquer的数的path的话,还需要更多空间)最后留下最大数,和
它的path,这时候的path应该是lgn的。理论上比较次数为 n+lgn-1,但是存储读写次
数增加很多,时间优化了吗?

【在 l*******b 的大作中提到】
: 没code,大约是这样做:
: 分成n/2对,没一对做比较取较小的一个。这样得到 n/2个数,找到这里面最小的两个
: ,然后用第二小的与最小的那个成对的数比较可以得到n个数里最小的两个
: (3 5) (4 2) (8 7)
: ---> 3 2 7 最小的两个3 2,用3 和 4比较得知2 , 3是所有里面最小的两个
: 回想一下感觉和建堆的复杂度类似

avatar
j*y
19
你这个是找max 和 min 吗?

【在 p*****2 的大作中提到】
: arr=[10,9,8,7,6,5,4,3]
: first=arr[0..1].max
: second=arr[0..1].min
: (2...arr.length).each do |i|
: if arr[i]>second
: if(arr[i]>first)
: second=first
: first=arr[i]
: else
: second=arr[i]

avatar
l*b
20
嗯,时间不优化吧,比较次数少,但没想出来怎么实现。感觉非常复杂

,

【在 c********t 的大作中提到】
: 明白了,多谢!
: 把你说的扩展为n,要开至少n空间,存所有path,(用map好些)divide and conquer,
: (如果每次不释放被conquer的数的path的话,还需要更多空间)最后留下最大数,和
: 它的path,这时候的path应该是lgn的。理论上比较次数为 n+lgn-1,但是存储读写次
: 数增加很多,时间优化了吗?

avatar
p*2
21

这题不是找max和min

【在 j*****y 的大作中提到】
: 你这个是找max 和 min 吗?
avatar
j*y
22
这个比较次数是 2n 吧?
最优的是 n + log n

【在 p*****2 的大作中提到】
: arr=[10,9,8,7,6,5,4,3]
: first=arr[0..1].max
: second=arr[0..1].min
: (2...arr.length).each do |i|
: if arr[i]>second
: if(arr[i]>first)
: second=first
: first=arr[i]
: else
: second=arr[i]

avatar
p*2
23

worst case 2n
n+logn需要额外空间吧?

【在 j*****y 的大作中提到】
: 这个比较次数是 2n 吧?
: 最优的是 n + log n

avatar
j*y
24
O(log n) 的 extra space

【在 p*****2 的大作中提到】
:
: worst case 2n
: n+logn需要额外空间吧?

avatar
p*2
25

这个优化真没啥意思。n+log(n)比2n好多少?还需要额外空间。

【在 j*****y 的大作中提到】
: O(log n) 的 extra space
avatar
b*s
26
是比较2n次啊。你遍历一遍和遍历两遍不是都要比较2n次吗?如果是worst case的话。

【在 c********t 的大作中提到】
: 弱问一句,难道不是遍历一遍就可以找出来两个最大的数吗?
:
: ★ 发自iPhone App: ChineseWeb 7.7

avatar
p*2
27

一般来说常数在时间复杂度的分析中可以忽略

【在 b********s 的大作中提到】
: 是比较2n次啊。你遍历一遍和遍历两遍不是都要比较2n次吗?如果是worst case的话。
avatar
b*s
28
我可以确定他不是问时间复杂度,而是问得比较次数,有没有可能小于2n次。我是没想
到,但是他说有的。

【在 p*****2 的大作中提到】
:
: 一般来说常数在时间复杂度的分析中可以忽略

相关阅读
logo
联系我们隐私协议©2024 redian.news
Redian新闻
Redian.news刊载任何文章,不代表同意其说法或描述,仅为提供更多信息,也不构成任何建议。文章信息的合法性及真实性由其作者负责,与Redian.news及其运营公司无关。欢迎投稿,如发现稿件侵权,或作者不愿在本网发表文章,请版权拥有者通知本网处理。