Careercup - Google面试题 - 6283958983589888

2014-05-06 11:31

题目链接

原题:

Find the k-th Smallest Element in Two Sorted Arrays. I followed the algorithm from this post, http://leetcode.com/2011/01/find-k-th-smallest-element-in-union-of.html 
But it does not handle the case where there are duplicates? Does anyone know how to do that? Also, in Java, how should we reduce the size of the arrays? I used the code below, but did not work.

题目:给定长度为n和m的两个有序数组,找出两数组合并后第K小的数,即升序排第K位的数。

解法1:又是这位“Guy”老兄发的题目,连链接都给贴出来了,明摆着告诉别人这题是他从别处copy来的。不得不说,这道题是非常具有区分度的一道简单题/难题。简单的做法,自然是O(K)时间的算法,在归并过程中就可以得出第K小的元素。

代码:

 1 // http://www.careercup.com/question?id=6283958983589888
 2 #include <algorithm>
 3 #include <cstdio>
 4 #include <vector>
 5 using namespace std;
 6 
 7 int findKthSmallest(vector<int> &a, vector<int> &b, int k)
 8 {
 9     int na, nb;
10     
11     na = (int)a.size();
12     nb = (int)b.size();
13     if (na == 0) {
14         return b[k];
15     } else if (nb == 0) {
16         return a[k];
17     } else if (a[0] > b[nb - 1]) {
18         return (k < nb ? b[k] : a[k - nb]);
19     } else if (b[0] > a[na - 1]) {
20         return (k < na ? a[k] : b[k - na]);
21     }
22     
23     int i, j;
24 
25     i = j = 0;
26     int res = a[i] < b[j] ? a[i++] : b[j++];
27     while (i + j <= k) {
28         if (i == na) {
29             res = b[j++];
30         } else if (j == nb) {
31             res = a[i++];
32         } else {
33             res = a[i] < b[j] ? a[i++] : b[j++];
34         }
35     }
36 
37     return res;
38 }
39 
40 int main()
41 {
42     vector<int> a, b;
43     int na, nb;
44     int i;
45     
46     while (scanf("%d%d", &na, &nb) == 2 && (na > 0 && nb > 0)) {
47         a.resize(na);
48         b.resize(nb);
49         for (i = 0; i < na; ++i) {
50             scanf("%d", &a[i]);
51         }
52         for (i = 0; i < nb; ++i) {
53             scanf("%d", &b[i]);
54         }
55         while (scanf("%d", &i) == 1) {
56             printf("%d\n", findKthSmallest(a, b, i));
57         }
58         a.clear();
59         b.clear();
60     }
61     
62     return 0;
63 }

解法2:这个代码不是我独立写出的,在参考了这篇文章的思路以后,模仿写了一版代码。此算法的复杂度应该是O(log(k))的,文章中说是O(log(n) + log(m))。解法中有个比较关键的思想,i + j = k - 1。如果某个a[i]恰好夹在b[j - 1]和b[j]之间,那么a[i]一定排在归并结果的第i + j + 1位,也就是第k位(从1算起)。反过来b[j]夹在a[i - 1]和a[i]之间道理也是一样的。理解这个道理一开始让我费了一番功夫,理解代码里的各种条件表达式则是另一番功夫了。

代码:

 1 // http://www.careercup.com/question?id=6283958983589888
 2 #include <algorithm>
 3 #include <climits>
 4 #include <cstdio>
 5 #include <vector>
 6 using namespace std;
 7 
 8 int findKthSmallest(vector<int> &a, vector<int> &b, int na, int nb, int ia, int d, int k)
 9 {
10     int ib = k - 1 - ia;
11     
12     int pre_a = ia == 0 ? INT_MIN : a[ia - 1];
13     int pre_b = ib == 0 ? INT_MIN : b[ib - 1];
14     int cur_a = ia == na ? INT_MAX : a[ia];
15     int cur_b = ib == nb ? INT_MAX : b[ib];
16     
17     if (cur_a >= pre_b && cur_a <= cur_b) {
18         return cur_a;
19     }
20     if (cur_b >= pre_a && cur_b <= cur_a) {
21         return cur_b;
22     }
23     
24     if (cur_a > cur_b) {
25         ia = (k - 1) - (ia - d) > nb ? (k - 1) - nb : ia - d;
26     } else {
27         ia = ia + d > na ? na : ia + d;
28     }
29     
30     return findKthSmallest(a, b, na, nb, ia, (d + 1) / 2, k);
31 }
32 
33 int main()
34 {
35     vector<int> a, b;
36     int na, nb;
37     int i;
38     int ia;
39     
40     while (scanf("%d%d", &na, &nb) == 2 && (na > 0 && nb > 0)) {
41         a.resize(na);
42         b.resize(nb);
43         for (i = 0; i < na; ++i) {
44             scanf("%d", &a[i]);
45         }
46         for (i = 0; i < nb; ++i) {
47             scanf("%d", &b[i]);
48         }
49         while (scanf("%d", &i) == 1) {
50             ia = min(na, i - 1);
51             printf("%d\n", findKthSmallest(a, b, na, nb, ia, (ia + 1) / 2, i));
52         }
53         a.clear();
54         b.clear();
55     }
56     
57     return 0;
58 }

 

转载于:https://www.cnblogs.com/zhuli19901106/p/3711251.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值