[leetcode]median of two sorted arrays求两个有序数组的中位数(扩展为第k大)

面试时被问到,想了想发现是《算法导论》原题(好像是顺序统计量和中位数那节)。由于平时不刷leetcode,这种题一般也只是想想,面试时写了个面向bug编程,不过感谢面试官手下留情。


问题

给定两个有序数组A,B,长度分别为n,m,求两个数组合并后中位数

要求时间O(log(n+m))


原始分析

将数组A,B分为A[0...\frac{n}{2}],A[\frac{n}{2}+1...n];B[0...\frac{m}{2}],B[\frac{m}{2}+1...n]四段

比较A[\frac{n}{2}],B[\frac{m}{2}],比如A[\frac{n}{2}]<B[\frac{m}{2}]时,B[\frac{m}{2}+1...n]不可能为答案

然后分治,接着就开始面向bug编程了


题解

扩展为kth问题,calc(a[],n,b[],m,k)表示求解函数

不考虑边界下,\forall ka =0,1,2,...,n <k,kb=k-ka

比较a[ka],b[kb]

a[ka]=b[kb]即说明答案为a[ka]

a[ka]<b[kb]说明答案为calc(a[]+ka,n-ka,b[],kb,k-ka)即前a[1,...,ka]不可能为答案

第三种情况同理

合理选取ka=min(\frac{k}{2},n)即可得到最优时间复杂度

#include 
#include 
#include 
#include 
#include 
using namespace std;

int calc(int *a, int n, int *b, int m, int k);

int main() {
  //
  int n, m;
  int a[105], b[105];
  n = 10, m = 15;
  for (int i = 1; i <= n; i++) a[i] = rand();
  for (int i = 1; i <= m; i++) b[i] = rand();
  sort(a + 1, a + 1 + n);
  sort(b + 1, b + 1 + m);
  for (int i = 1; i <= n; i++) printf("%d%c", a[i], (i == n) ? '\n' : ' ');
  for (int i = 1; i <= m; i++) printf("%d%c", b[i], (i == m) ? '\n' : ' ');
  for (int i = 1; i <= n + m; i++) printf("%d %d\n", i, calc(a, n, b, m, i));
  return 0;
}

int calc(int *a, int n, int *b, int m, int k) {
  if (n > m) return calc(b, m, a, n, k);
  if (!n) return b[k];
  if (k == 1) return min(a[1], b[1]);
  int ka = min(k / 2, n), kb = k - ka;
  if (a[ka] < b[kb])
    return calc(a + ka, n - ka, b, m, k - ka);
  else if (a[ka] > b[kb])
    return calc(a, n, b + kb, m - kb, k - kb);
  else
    return a[ka];
}

 

你可能感兴趣的:([leetcode]median of two sorted arrays求两个有序数组的中位数(扩展为第k大))