SELECTION IN X + Y,二维数组的Top K问题

2020-08-23  本文已影响0人  devilisdevil

algorithm: SELECTION IN X + Y AND MATRICES WITH SORTED ROWS AND COLUMNS *
leetcode: 378. Kth Smallest Element in a Sorted Matrix

问题描述

n \times n的二维数组,行列均有序,寻找第k大元素

为了方便对算法理解,这里假设行列的数都是递增的,比如像下面这样:

Example Matrix

算法分析

思想:分治 divide-and-conquer

一些定义:

符号 说明
A n \times n的矩阵/二维数组
\overline{n} \left \lceil \frac{1}{2} (n+1) \right \rceil
\overline{A} A\overline{n} \times \overline{n}大小的子矩阵,取A的奇数行列得到(外加最后一行/列,如果n是偶数),
rank^+(A, a)/rank^-(A, a) 集合(矩阵)A中大于/小于a的元素个数

例如,6 \times 6的矩阵A对应的子矩阵\overline{A}由黄色块组成

the submatrix of A

算法主要需要实现两个函数:biselectpick

pick

函数功能:求第k小元素 (the k-th element of L)

一般quickselect的最坏复杂度是O(nlogn),但若运用上median of medians(BFPRT算法,选取中位数附近的数作为partition的点),最坏复杂度可降为O(n),所以该paper也是使用的这个O(n)的算法。
关于该算法的讲解,参考我另一篇文章:中位数的中位数 - Median of Medians,选取近似的中位数作为pivot元素,这里不再赘述,最后总的实现可以看我github上的代码。

biselect

函数功能:选取方阵中的两个元素,第k_1小和第k_2小元素。而如果我们需要寻找第k小的元素,直接传参k_1=k_2=k就行了

biselect pseudo code

上面是paper中的伪代码,这里对ra^-rb^+L的计算可以同时进行,如下:(这里的矩阵是右下角对应最大,左上角最小,如果矩阵的行列排序不同的话你可能需要调整一些加减符号,但计算的思想可以借鉴)

int ra_less = 0, rb_more = 0;
vector<int> L;
int ja = n, jb = n;
for (int i = 0; i < n; ++i) {
  while (ja > 0 && A(i, ja - 1) >= a) --ja;
  ra_less += ja;
  while (jb > 0 && A(i, jb - 1) > b) --jb;
  rb_more += n - jb;
  //                  jb   ja
  // each row: ---bbb[x]xx[a]aa+++
  // append x's to L (b < x < a)
  for (int ii = jb; ii < ja; ++ii) L.push_back(A(i, ii));
}

最后最重要的是分治算法的combine部分:计算x和y的值并返回

line of elements.png

如上图,要明白伪代码最后几行判断条件,只要理解上面这个图就ok了。

现在自己再去理解上面的几个判断条件吧。。
关键在于为什么\overline{k}_1\overline{k}_2这么赋值,请看下面的正确性说明。

正确性

TODO

示例代码

github

参考

上一篇 下一篇

猜你喜欢

热点阅读