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 }