在部分有序的数组中查找元素

16

我得到了以下的面试问题。

有一个n x n元素的数组。该数组部分排序,即第i行中最大的元素小于第i+1行中最小的元素。如何在O(n)的复杂度下找到给定的元素。

这是我的解决方案:

您应该前往第n/2行。从那里开始比较,例如您搜索100并且您看到的第一个数字是110,那么您知道它要么在这一行中,要么在上面的行中,现在您走n/4行,以此类推。

从评论中得知:

总体而言, 不是 O(n * log n) 吗?因为他必须在每个二进制搜索达到的行中进行解析, 因此线性搜索的数量与他将要扫描的行数相乘。- Martin Matysiak 5分钟前。

我不确定这是一个正确的解决方案。有没有更好的方法?


9
听起来对我来说是正确的。O(log n)用于将候选行减少到两行,O(n)用于在这两行中找到元素。总的时间复杂度为O(n)。 - hammar
在已排序的数组中,你找不到比二分查找更好的方法;而在未排序的数组中,你也找不到比线性查找更好的方法。因此,在我看来,这似乎是最优的选择。 - sverre
1
正确。先进行二分查找,然后进行线性查找。由于未排序的行,最好的时间复杂度不会超过O(n)。 - TheFogger
1
总的时间复杂度不是O(n * log n)吗?他必须在每次二分查找时解析到达的每一行,因此线性搜索的数量乘以他平均需要扫描的行数。 - Martin Matysiak
我认为马丁是正确的,有人有O(n)的实现思路吗? - YAKOVM
O(n)中的“n”是指nxn中的“n”吗? - CMR
2个回答

15

你的解决方案确实是O(n log n),假设你搜索了解析的每一行。如果不搜索每一行,则无法准确执行二进制步骤。

O(n)解决方案:

选择第n/2行,而不是搜索整行,我们只需取前一行的第一个元素和下一行的第一个元素。 O(1)
我们知道n/2行的所有元素必须在这些选定的值之间(这是关键观察)。 如果目标值位于区间内,则搜索所有三行(3 * O(n) = O(n))。

如果我们的值超出了这个范围,那么按二分搜索的方式继续选择n/4(如果我们的值小于范围),并选择3n/4行(如果该值更大),然后再与相邻行的一个元素进行比较。

找到正确的3行块将花费O(1) * O(log n),找到元素将花费O(n)

总计O(log n) + O(n) = O(n)


实际上,通过搜索行并将其与行的第一个(或任何)值进行比较,您将可能的行限制为2而不是3。 - dcn
@dcn,不是这样的。在{ 1 2 3 ; 4 5 6 ; 8 7 9 }中搜索任何一个{2,5,7}都会发现目标确实在范围[1,8]内,但如果我不搜索所有3行,就找不到我需要的值之一。 - davin
  1. 比较大小:搜索“2”。与“5”比较,哪个更大->只能在第1和第2行中。同样的论点适用于搜索5和7。
- dcn
我的错。我以为你是在将它与连续行的元素进行比较,但再次阅读后,prev和next并不应该是相邻的。 - dcn
2
当然,你可以像这样将其缩减为2个可能的行:通过二分查找,找到一个行的最小索引 maxrow ,使得 maxrow 的第一个元素比你要查找的元素大。然后只有 maxrowmaxrow-1 是候选项。 - dcn
显示剩余3条评论

3

这里有一个简单的实现 - 因为我们无论如何需要在一行中查找元素的时间复杂度为O(n),所以我省略了二分查找...

void search(int n[][], int el) {
    int minrow = 0, maxrow;
    while (minrow < n.length && el >= n[minrow][0])
        ++minrow;
    minrow = Math.max(0, minrow - 1);
    maxrow = Math.min(n.length - 1, minrow + 1);
    for (int row = minrow; row <= maxrow; ++row) {
        for (int col = 0; col < n[row].length; ++col) {
            if (n[row][col] == el) {
                System.out.printf("found at %d,%d\n", row, col);
            }
        }
    }
}

起初我对你为什么要通过行进行线性搜索感到困惑,但后来恍然大悟... O(n) + O(n) = O(log n) + O(n) = O(n),所以如果不需要的话,为什么要花哨呢! :) (当然,如果它是一个m*n矩阵,那么为了最优化,你仍然需要二分搜索...) - j_random_hacker
@dcn - 你能解释一下计算minrow和maxrow的逻辑吗? - Neel

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接