二分法与三分法

二分查找

基于分治策略的一种查找方法, 时间复杂度 O ( l o g 2 n )

是用于解决单调有序问题,缩小问题规模

算法步骤

  • 将左指针指向序列首元素,右指针指向队尾元素
  • = + 2
  • 若中间指针指向的值大于目标值,则我们向左继续查找,右指针 = 中间指针 - 1
  • 若中间指针指向的值小于目标值,则我们向右基础查找,左指针 = 中间指针 + 1
  • 以此方法递归求解问题即可

代码演示:

int binary_search1(int *num, int n, int x) {
    int head = 0, tail = n - 1, mid;
    while (head <= tail) {
        mid = (head + tail) >> 1;
        if (num[mid] == x) return mid;
        if (num[mid] < x) {
            head = mid + 1;
        }else {
            tail = mid - 1;
        }
    }
    return -1;
}

二分问题模型:

  • 11110000问题(满足特定条件的最小值,最后的 1)
  • 00001111问题(满足特定条件的最大值,最先的 1)

11110000问题:

​ 首先我们需要明确我们的目的是为了不断缩小问题规模,也就是说最终答案已经要包含在我们的问题区间内。

​ 像二分法一样我们进行二分查找,我们通过中间指针指向的值来缩小问题区间,如果我们发现中间值为0,那么我们的右指针可以放心大胆的跨度到中间指针前一位。如若我们发现中间值为1,那我们不能确定这个值是否为最终结果,那我们只能将左指针指向中间指针的位置。

我们需要注意全1并为偶数的情况, 如若现在序列为 11, 也就是序列中间指针都指向中间靠左的元素,那么右指针将永远不会更改,最终造成死循环

解决方法: = + + 1 2

每次将中间指针指向中间靠右的元素将会解决这个问题。

代码演示:

int binary_search2(int *num, int n, int x) {
    int head = -1, tail = n - 1, mid;
    while (head < tail) {
        mid = (head + tail + 1) >>1; 
        if (num[mid] == 1) {
            head = mid;
        } else {
            tail = mid - 1;
        }
    }
    return head;
}

00001111问题:

和上述问题我们要达到的目的一样也是为了不断的缩小问题规模。

那么求解问题的方法和求解00001111也是不禁相同。当我们发现中间值为0时,我们知道中间值不满足条件,那么我们的左指针可以放心大胆的向右前进,左指针 = 中间指针 + 1。当我们发现中间值为1时,我们不能保证这个是问题答案,那我们右指针只能小心翼翼的向左前进。右指针 = 中间指针。

由于我们就要取靠左的值所以正常求解即可

代码演示:

int binary_search3(int *num, int n, int x) {
    int head = 0, tail = n, mid;
    while (head < tail) {
        mid = (head + tail) >> 1;
        if (num[mid] == 1) {
            tail = mid;
        } else {
            head = mid + 1;
        }
    }
    return head == n ? -1:head;
}

三分查找

适用于解决单峰问题,要保证L与R在问题答案的左右两侧。

代码演示:

#include <stdio.h>
#include <math.h>
#define EPS 1e-6
double f(double x, double a, double b, double c) {
    return a*x*x + b*x + c;
}
double three_point_search(double a, double b, double c) {
    double head = -10000, tail = 10000, m1, m2;
    if (a > 0) {
        a = -a, b = -b, c = -c;
    }
    while (fabs(tail - head) > EPS) {
        m1 = (tail - head) / 3.0 + head;
        m2 = (tail - head) / 3.0 * 2 + head;
        if (f(m1,a,b,c) < f(m2, a, b, c)) {
            head = m1;
        }else {
            tail = m2;
        }
    }
    return head;
}
int main() {
    double a, b, c;
    while (~scanf("%lf %lf %lf", &a, &b, &c)) {
        printf("%f\n", three_point_search(a, b, c));
    }
}

猜你喜欢

转载自blog.csdn.net/Ruger008/article/details/81839862
今日推荐