这是How to compare each element in two arrays with time complexity less than O(n^2)的概括。假设我们有两个矩阵A和B,其大小分别为nxk和mxk,分别可寻址为A[row][col]
和B[row][col]
。如果每个(i, j)
,r
都允许一对A[i][r] >= B[j][r]
。有什么方法可以比天真的O(nmk)更快地识别每个可接受的对
for (int i = 0; i < n; ++i) {
for (int j = 0; j < m; ++j) {
bool accept = true;
for (int r = 0; r < k && accept; ++r) {
accept &= (A[i][r] >= B[j][r]);
}
if (accept) { std::cout << i << ", " << j << "\n"; }
}
}
?
如果k = 1,那么我可以使用链接的问题隐含的解决方案在n log n次内完成任务。但是,当k> 1时,由于诸如此类的矩阵而变得更加困难:
A[0] = {1, 1}
A[1] = {3, 1}
A[2] = {3, 5}
A[3] = {5, 3}
A[4] = {5, 5}
B[0] = {2, 4}
B[1] = {4, 2}
可接受的对是(2,0),(4,0),(3,1)和(4,1)。按第一个元素排序给出上面的顺序,其中B = 1可接受的是连续的(A = 3和A = 4),而B = 0可接受的不是。类似地,按第二个元素排序使B = 0可接受的内容连续,而B = 1可接受的内容不连续。一遍排序和读取类似k = 1解决方案的连续范围似乎不起作用。
我要考虑的特定设置的n和m大约为数百万,而k大约为一千,所以nmk时间不是很实用。
答案 0 :(得分:0)
输出大小可以为nm
,因此该算法的性能不能超过O(nm)。当然,可以提高平均水平,但在很大程度上取决于您的数据和分布。以下是一些通用提示:
如果您负担得起m * k内存,则可以保留按第一列值排序的B索引的排序列表。第二列相同,依此类推。通过这种结构+二进制搜索,您可以回答给定固定列c和固定数x的问题,即O(log m)中有多少B [j] [c] <= x。
然后对于A [i]中的每个值x,您可以检查有多少B [j] [c] <= x。按此数量对它们进行排序。第一个值(将其称为L1)将是最小的数字,因此您将通过该列与排序列表中的B进行比较。通过使用二进制搜索,您可以跳过开头,仅与B的L1数组进行比较。
您可以按照从B [j] [c] <= x计算中保留的顺序进行比较,而不必以任何顺序逐列进行比较。这将意味着我们从A使用的第二个值相对于其余列低于B中的列的机会最小。这将有助于最大程度地减少对不满足条件的对的比较。 >