• III.二分算法


    目录

    A.程序或算法的时间复杂度

    B.二分查找 

    C.求方程的根

    D.寻找指定和的整数对

    E.Aggressive cows 


    A.程序或算法的时间复杂度


    • 在无序数列中查找某个数(顺序查找) O(n)
    • 平面上有n个点,要求出任意两点之间的距离 O(n2)
    • 插入排序、选择排序、冒泡排序 O(n2)
    • 快速排序 O( n*log(n))
    • 二分查找O(log(n))

    B.二分查找 


    题目描述

    A心里想一个1-1000之间的数,B来猜,可以问问题,A只能回答是或否。怎么猜才能问的问题次数最少?

    题目解答

    每次缩小猜测范围到上次的范围的一半,只需要10次

    • 写一个函数BinarySeach,在包含size个元素的、从小到大排序的int数组a里查找元素p,如果找到,则返回元素下标,如果找不到,则返回-1。要求复杂度O(log(n))
    1. int BinarySearch(int a[],int size,int p)
    2. {
    3. int L = 0;//查找区间的左端点
    4. int R = size - 1;//查找区间的右端点
    5. while( L<=R )//如果查找区间不为空就继续查找
    6. {
    7. int mid = L + (R-L)/2;//取查找区间正中元素的下标
    8. if( p == a[mid] )
    9. return mid;
    10. else if( p > a[mid] )
    11. L = mid + 1;//设置新的查找区间的左端点
    12. else
    13. R = mid - 1;; //设置新的查找区间的右端点
    14. }
    15. return -1;
    16. }//复杂度O(log(n))
    •  写一个函数LowerBound,在包含size个元素的、从小到大排序的int数组a里查找比给定整数p小的,下标最大的元素。找到则返回其下标,找不到则返回-1
    1. int LowerBound(int a[],int size,int p)//复杂度O(log(n))
    2. {
    3. int L = 0;//查找区间的左端点
    4. int R = size - 1;//查找区间的右端点
    5. int lastPos = -1;//到目前为止找到的最优解
    6. while( L<=R )//如果查找区间不为空就继续查找
    7. {
    8. int mid = L + (R-L)/2;//取查找区间正中元素的下标
    9. if(a[mid]>=p)
    10. R = mid - 1;
    11. else
    12. {
    13. lastPos = mid;
    14. L = mid + 1;
    15. }
    16. }
    17. return lastPos;
    18. }

     注意

            int mid = (L+R)/2; //取查找区间正中元素的下标

    为了防止 (L+R)过大溢出:

            int mid = L+(R-L)/2;

    C.求方程的根

    题目描述

    求下面方程的一个根:f(x) = x3-5x2+10x-80 = 0若求出的根是a,则要求 |f(a)| <= 10-6

    题目解答

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

    1. #include
    2. #include
    3. double EPS = 1e-6;
    4. double f(double x)
    5. {
    6. return x*x*x - 5*x*x +10*x - 80;
    7. }
    8. int main()
    9. {
    10. double root, x1 = 0, x2 = 100;
    11. root = x1 + (x2-x1)/2;
    12. int triedTimes = 1;
    13. double y;
    14. y = f(root);
    15. while( fabs(y) > EPS)
    16. {
    17. if( y > 0 )
    18. x2 = root;
    19. else
    20. x1 = root;
    21. root = x1 + (x2 - x1)/2;
    22. y = f(root);
    23. triedTimes ++;
    24. }
    25. printf("%.8f\n",root);
    26. printf("%d",triedTimes);
    27. return 0;
    28. }

    D.寻找指定和的整数对

    题目描述

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

    解法一:

            用两重循环,枚举所有的取数方法,复杂度是O(n2)的。

    1. for(int i = 0;i < n-1;i++)
    2. {
    3. for(int j = 0;j < n;j++)
    4. {
    5. if( a[i]+b[j] == m)
    6. break;
    7. }
    8. }

     解法二:

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

    解法三:(x)

    • 将数组排序,复杂度是O(n×log(n))
    • 查找的时候,设置两个变量i和j,i初值是0,j初值是n-1.看a[i]+a[j],如果大于m,就让j减1,如果小于m,就让i加1,直至a[i]+a[j]=m。
    1. #include
    2. #include
    3. int int_cmp(const void* e1, const void* e2)
    4. {
    5. return *(int*)e1 - *(int*)e2;//升序排序
    6. }
    7. int main()
    8. {
    9. int n;
    10. scanf("%d",&n);
    11. int a[100001];
    12. for(int i=0;i < n;i++)
    13. {
    14. scanf("%d",&a[i]);
    15. }
    16. qsort(a, n, sizeof(a[0]), int_cmp);
    17. int m;
    18. scanf("%d",&m);
    19. int i = 0, j = n-1;
    20. if( a[i] + a[j] > m)
    21. j--;
    22. else if( a[i] + a[j] < m)
    23. i++;
    24. else
    25. printf("%d + %d == %d",a[i],a[j],m);
    26. return 0;
    27. }

    E.Aggressive cows 

    题目描述

    农夫 John 建造了一座很长的畜栏,它包括N (2≤N≤100,000)个隔间,这些小隔间的位置为x0,...,xN-1 (0≤xi≤1,000,000,000,均为整数,各不相同).
    John的C (2≤C≤N)头牛每头分到一个隔间。牛都希望互相离得远点省得互相打扰。怎样才能使任意两头牛之间的最小距离尽可能的大,这个最大的最小距离是多少呢?

    解法一:

    先得到排序后的隔间坐标 x0,...,xN-1
    从1,000,000,000/C到1依次尝试这个 “最大的最近距离”D,找到的第一个可行的就是答案。

    尝试方法:

    1)    第1头牛放在x0
    2)    若第k头牛放在xi ,则找到xi+1到xN-1中第一个位于[xi+D, 1,000,000,000]中的Xj ,第k+1头牛放在Xj。找不到这样的Xj,则 D=D-1,转 1)再试若所有牛都能放下,则D即答案

    解法二:(x)

    先得到排序后的隔间坐标 x0,...,xN-1
    在[L,R]内用二分法尝试“最大最近距离”D = (L+R)/2 (L,R初值为[1,  1,000,000,000/C]
    若D可行,则记住该D,然后在新[L,R]中继续尝试(L= D+1)
    若D不可行,则在新[L,R]中继续尝试(R= D-1)

    1. #include
    2. bool check(int mid,int a[],int n,int m)
    3. {
    4. int cnt = 1;
    5. int cur = a[0];
    6. for(int i =1;i < n;i++)//从第二头牛开始放
    7. {
    8. if(a[i]-cur >= mid)
    9. {
    10. cnt++;//放下则数量加一
    11. cur = a[i];//如果放下,则将当前的牛栏作为初始继续往后找可以放的下的
    12. }
    13. }
    14. if(cnt>=m)//在给定的值下能够放下的牛的个数大于m,则说明给的值小了
    15. return true;
    16. else
    17. return false;
    18. }
    19. int main()
    20. {
    21. int n,m;
    22. scanf("%d %d",&n,&m);
    23. int a[100000];
    24. for(int i =0;i < n;i++)
    25. {
    26. scanf("%d",&a[i]);
    27. }
    28. sort(a,a+n);
    29. int left = 0, right = a[n-1];//二分取值
    30. int mid = left + (right-left)/2;
    31. while(left<=right)
    32. {
    33. if( check(mid,a,n,m) )
    34. left = mid + 1;
    35. else
    36. right = mid - 1;
    37. mid = left + (right-left)/2;
    38. }
    39. printf("%d",right);
    40. }

  • 相关阅读:
    C语言学习笔记(五)
    剧本杀市场仍在快速发展,剧本杀小程序成为了新的机遇
    写一个名为Rectangle的类表示矩形
    解决Opencv dnn模块无法使用onnx模型的问题(将onnx的动态输入改成静态)
    学生个人网页设计作品:旅游网页设计与实现——成都旅游网站4个页HTML+CSS web前端网页设计期末课程大作业 学生DW静态网页设计 学生个人网页设计作品
    基于蒙特卡洛的大规模电动汽车充电行为分析(Matlab代码实现)
    Rust基础入门之变量绑定与解构
    【跨境电商】提高客户留存率的 9 种策略
    C1W1.LAB.Preprocessing+Word frequencies+Logistic_regression_model
    Spring Boot、Spring Cloud 自定义配置文件(如何整合配置中心)
  • 原文地址:https://blog.csdn.net/2301_80391227/article/details/136128604