[分治] 二分查找之单个元素、可重复元素上下界

单个元素

目的:在一个不重复的序列里,找一个元素,找不到返回-1。

// A:元素所在数组   [x,y):区间   v:元素值
int bserach(int* A, int x, int y, int v) {
    int m;
    while (x < y) {
        m = x + (y - x) / 2;
        if (A[m] == v) return m;
        else if (A[m] > v) y = m;
        else x = m + 1;
    }
    return -1;
}

思路就很明了了。

找下界

目的:当v存在时返回它出现的第一个位置。如果不存在,返回这样一个下标i:在此处插入v(此处元素往后移)后序列仍有效。

int lower_bound(int* A, int x, int y, int v) {
    int m;
    while (x < y) {
        m = x + (y - x) / 2;
        if (A[m] >= v) y = m;
        else x = m + 1;
    }
    return x;
}

这就有点说头了。(引自 aoapc2 by LRJ)
首先,最后的返回值不仅可能是x, x+1, x+2, …, y-1, 还可能是y——如果v大于A[y-1],就只能插入这里了。这样,尽管查找区间试左闭右开区间[x,y),返回值的候选区间却是闭区间[x,y]。A[m]和v的各种关系所带来的影响如下。

  • A[m] = v: 至少已经找到一个,而左边可能还有,因此区间变为[x,m]。
  • A[m] > v: 所求位置不可能在后面,但有可能是m,因此区间变为[x,m]。
  • A[m] < v: m和前面都不可行,因此区间变为[m+1,y]。

求上界

目的:当v存在时返回它出现的最后位置。如果不存在,返回这样一个下标i:在此处插入v(此处元素往后移)后序列仍有效。

int upper_bound(int* A, int x, int y, int v) {
    int m;
    while (x < y) {
        m = x + (y - x) / 2;
        if (A[m] <= v) x = m+1;
        else y = m;
    }
    return x;
}

同样,查找区间为[x,y),而返回值的候选区间是[x,y]。
因此,A[m]和v的各种关系所带来的影响如下:

  • A[m] = v: 至少已经找到一个,而右边可能还有,所以区间变为[m+1,y]。
  • A[m] < v: m没可能,左边也没可能,所以区间变为[m+1,y]。
  • A[m] > v: m依旧有可能,右边没可能,所以区间变为[x,m]。

猜你喜欢

转载自blog.csdn.net/icecab/article/details/80463784