《程序设计与算法》第三章【二分算法】

44 篇文章 1 订阅

二分查找

int BinarySearch(int a[], int size, int p) {
    int L = 0;                 // 查找区间的左端点
    int R = size - 1;          // 查找区间的右端点
    // int lastPos = -1;          // 到目前为止找到的最优解
    while (L <= R) {           // 如果查找区间不为空就继续查找
        int mid = L+(R-L)/2;   // 取查找区间正中元素的下标
        if (p == a[mid])
            return mid;
        else if (p > a[mid])
            L = mid + 1;       // 设置新的查找区间的左端点
        else {
            // lastPos = mid;
            R = mid - 1;       // 设置新的查找区间的右端点
        }
    }
    // return lastPos;
    return -1;
}  // 复杂度O(nlog(n))

二分法求方程的根

题目描述
求下面方程的一个根:f(x) = x^3 - 5x^2 + 10x - 80 = 0
若求出的根是a,则要求 |f(a)| <= 10^-6

解题思路
对f(x)求导,得f’(x) = 3x^2 - 10x + 10。由一元二次方程求根公式知方程f’(x) = 0无解,因此f’(x) 恒大于0.故f(x)是单调递增的,易知f(0) < 0且f(100) > 0,所以区间[0,100]内必然有且只有一个根。由于f(x)在[0,100]内是单调的,所以可以用二分法在区间[0,100]中寻找根。

解答

#include <cstdlib>
#include <iostream>
#include <cmath>
using namespace std;
double EPS = 1e-6;
double f(double x) {
    return x*x*x - 5*x*x + 10*x - 80;
}
int main() {
    double root, x1 = 0, x2 = 100, y;
    root  = x1+(x2-x1)/2;
    int triedTimes = 1;   // 记录一共尝试了多少次,对求根来说不是必须的
    y = f(root);
    while (fabs(y) > EPS) {
        if (y > 0)
            x2 = root;
        else
            x1 = root;
        root = x1+(x2-x1)/2;
        y = f(root);
        triedTimes++;
    }
    printf("%.8f\n", root);
    printf("%d\n", triedTimes);
    return 0;
}

寻找指定和的整数对

题目描述
输入n ( n<= 100,000)个整数,找出其中的两个数,它们之和等于整数m(假定肯定有解)。题中所有整数都能用 int 表示。

解题思路

解法1:用两重循环,枚举所有的取数方法,复杂度是O(n 2 )的。

for(int i = 0;i < n-1; ++i)
    for(int j = i + 1; j < n; ++j)
        if( a[i]+a[j] == m)
            break;

100,000^2 = 100亿,在各种OJ上提交或参加各种程序设计竞赛,这样的复杂度都会超时 !

解法2:
1. 将数组排序,复杂度是O(n*log(n))
2. 对数组中的每个元素a[i],在数组中二分查找m-a[i],看是否能找到。复杂度O(log(n)),最坏要查找n-1次,所以查找这部分的复杂度也是O(n*log(n))

这种解法总的复杂度是O(n*log(n))的。

解法3:
1. 将数组排序,复杂度是O(n*log(n))
2. 查找的时候,设置两个变量i和j,i初始值是0,j初始值是n-1,看a[i] + a[j],如果大于m,就让j减1,如果小于m,就让i加1,直到a[i] + a[j] = m。

这种解法总的复杂度是O(n*log(n))的。

查找学生信息

查找学生信息

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;

struct Student {
    char id[100];
    char name[100];
    char sex[5];
    int age;
    bool operator < (const Student& A) const {
        return strcmp(id, A.id) < 0;
    }
} stu[1005];
int main() {
    int n;
    while (scanf("%d", &n) != EOF) {
        for (int i = 0; i < n; i++) {
            scanf("%s%s%s%d", stu[i].id, stu[i].name, stu[i].sex, &stu[i].age);
        }
        sort(stu, stu+n);
        int t;
        scanf("%d", &t);
        while (t--) {
            int ans = -1;
            char x[30];
            scanf("%s", x);
            int low = 0, high = n-1;
            while (low <= high) {
                int mid = low + (high-low)/2;
                int tmp = strcmp(stu[mid].id, x);
                if (tmp == 0) {
                    ans = mid;
                    break;
                } else if (tmp > 0)
                    high = mid - 1;
                else
                    low = mid + 1;
            }
            if (ans == -1)
                printf("No Answer!\n");
            else
                printf("%s %s %s %d\n", stu[ans].id, stu[ans].name, stu[ans].sex, stu[ans].age);
        }
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值