首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >查找是否存在i的算法,以使array[i]等于i

查找是否存在i的算法,以使array[i]等于i
EN

Stack Overflow用户
提问于 2010-11-04 20:38:53
回答 9查看 25.6K关注 0票数 11

我收到了我的CS教授的作业:

在O(logn)时间中,如果在给定的由不同整数组成的预先排序数组中有一个索引i,则arrayi = i.证明时间是O(logn)。

更新:整数可以是负数,0或正数。

好吧,所以我有点纠结于这件事。我的想法是:

使用二进制搜索,只有当arraymid <= startindex,其中mid是中间元素的索引,startindex是数组的开始时,才能确定中间元素左侧没有这样的值。

数组的右半部分对应的规则是arraymid >= startindex + numel,其中上述变量和numel是mid的正确元素数。

这看起来不像O(logn),因为在最坏的情况下,我必须遍历整个过程,对吗?有人能给我一个正确的方向吗,或者告诉我这是可行的?

我怎么才能正式证明这一点?我并不是要求一个明确的答案,而是需要更多的帮助来让我理解。

在C中:

代码语言:javascript
复制
int _solve_prob_int(int depth, int start, int count, int input[])
    {
    if(count == 0)
        return 0;
    int mid = start + ((count - 1) / 2);
    if(input[mid] == mid)
        return 1;

    if(input[mid] <= start && input[mid] >= start + count)
        return 0;

    int n_sub_elleft = (int)(count - 1) / 2;
    int n_sub_elright = (int)(count) / 2;

    if(input[mid] <= start)
        return _solve_prob_int(depth + 1, mid + 1, n_sub_elright, input);

    if(input[mid] >= start + count)
        return _solve_prob_int(depth + 1, mid - n_sub_elleft, n_sub_elleft, input);

    return _solve_prob_int(depth + 1, mid - n_sub_elleft, n_sub_elleft, input) ||
            _solve_prob_int(depth + 1, mid + 1, n_sub_elright, input);
    }

测试用例:

代码语言:javascript
复制
Sorted args: 1 2 3 4 5 6 7 8 9 10 11 12 : 
Start: 0, count: 12, mid: 5 value: 6
    Start: 0, count: 5, mid: 2 value: 3
        Start: 0, count: 2, mid: 0 value: 1
            Start: 1, count: 1, mid: 1 value: 2
        Start: 3, count: 2, mid: 3 value: 4
            Start: 4, count: 1, mid: 4 value: 5
    Start: 6, count: 6, mid: 8 value: 9
        Start: 6, count: 2, mid: 6 value: 7
            Start: 7, count: 1, mid: 7 value: 8
        Start: 9, count: 3, mid: 10 value: 11
            Start: 9, count: 1, mid: 9 value: 10
            Start: 11, count: 1, mid: 11 value: 12

以上是我的程序运行与一些输出,根据它的搜索。对于1-12的列表,它以索引5为中心,确定在索引0-4处有一个介于0-4之间的值。它还确定在索引6-11处有一个介于6-11之间的值.因此,我开始搜索他们两个。这样做不对吗?

EN

回答 9

Stack Overflow用户

回答已采纳

发布于 2010-11-04 20:49:09

整数是区分和排序的。

给我这样的array[i] = i,你有array[i] - i = 0

对于每一个jarray[j] - j <= 0,对于j>我,有array[j] - j >= 0,因为j在每一步都有1的变化,但是arrayj至少有1的变化(不同的和排序的数字)。

左边是<=0,右边是>= 0

使用二分法,您可以很容易地找到正确的位置在O(log n)

请注意,您只需要找到一个元素,而不是所有元素。在您的示例中,所有元素都正常工作,但您只需要其中一个元素。如果你想把它们全部打印出来,那就是O(n)

票数 14
EN

Stack Overflow用户

发布于 2010-11-04 21:29:44

想象一下二进制搜索,就像在字典中查找一个单词。首先,你可以把这本书打开到字典的中心,看看页面顶部的单词是在前、后还是等于你要找的单词。如果是后面,你把字典的后半部分分成两部分,并检查那一半的中间部分。在查看了页面的顶部之后,你将搜索的范围缩小到了大约四分之一的字典范围内。继续这个过程,直到您发现这个单词在您正在查看的页面的某个位置。然后使用类似的过程在页面上找到单词。

这个过程不是O(n),因为您不必查看每个页面上的每个单词,即使是在最坏的情况下。这是O(log ),因为通过每一步,您都可以删除字典中大约一半的内容,因为它不包含您要查找的单词。

编辑

对不起,我误解了原来的问题。

在这种情况下,关键是要认识到所谓的“鸽子洞原理”,即你只能把尽可能多的鸽子放进洞里,因为你有洞可以把它们放进去。(让学术界为这么简单的想法想出一个名字吧!)

考虑以下情况:

代码语言:javascript
复制
0 1 2 3 4 5 6

在这里,所有的array[i]都等于i,所以当您第一次开始二进制搜索时,您将立即得到一个肯定的答案。

现在让我们从底部取一个数字:

代码语言:javascript
复制
0 1 3 4 5 6

当您执行二进制搜索时,您会发现这个array[3] > 3,并且您可以正确地推断出,在这个枢轴点之上的任何值都不可能使array[i] == i。这是因为列表是有序的和唯一的,所以您不能以这样的组合结束:

代码语言:javascript
复制
0 1 3 4 5 5 6
0 1 3 4 6 5 7

一旦array[i]被确定为大于ii和任何给定的n之间就没有足够的数字来允许数组中的下一个元素接近i。同样,如果您确定array[i]小于i,那么在查看数组的开头时,您没有足够的“空白”来“赶上”i

因此,在每一步中,您都可以正确地消除数组的一半,就像查找字典一样,确定在O(log )时间内是否有任何array[i] == i

票数 9
EN

Stack Overflow用户

发布于 2011-08-09 13:54:28

这是一个二进制搜索问题,的密钥不给。在OP的问题中,关键是中间本身!就是这样,在每个子数组中搜索中间元素。

使用二进制搜索的解决方案的伪代码:

代码语言:javascript
复制
    while (low and high don't meet)
        mid = (low + high) / 2
        if (arr[mid] < mid)
            high = mid - 1
        else if (arr[mid] > mid)
            low = mid + 1
        else // we found it!
            return mid;
    // end while
    return -1; // indicates there is no such i
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/4101141

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档