二分查找是针对某个条件,可以把把解空间分为两类,并通过中点所在的类,每次排除一半的解空间。

Acwing. 789 数的范围【整数二分】

该题的题意让我们找到某个数在排序数组中的坐标范围,比如1 2 2 3 3 4。
由于数组是排好序的,因此我们可以考虑二分来做。
首先我们先确定左边界,我们可以把>=target的划分为右类,如果我们的中点mid在右类,由于我们要求右类最小的数,因此需要砍掉mid右边的数,mid由于可能是最终解,不能排除。
如果我们的中点mid在左类,那mid左边包括mid肯定不是我们要求的答案,砍掉。
最终得到左边界。

  1. int get_left(int target) {
  2. int left = 0, right = n - 1;
  3. while(left < right) {
  4. int mid = (left + right) >> 1;
  5. if (d[mid] >= target) {
  6. right = mid;
  7. } else {
  8. left = mid + 1;
  9. }
  10. }
  11. if (d[right] == target) {
  12. return right;
  13. } else {
  14. return -1;
  15. }
  16. }

右边界的求法类似,我们可以把<=target的划分为左类,如果我们的中点mid在右类,那mid右边包括mid肯定不是我们要求的答案,砍掉。
如果我们的中点mid在左类,由于我们要求左类最大的数,因此需要砍掉mid左边的数,mid由于可能是最终解,不能排除。
最终得到右边界。

  1. int get_right(int target) {
  2. int left = 0, right = n - 1;
  3. while(left < right) {
  4. int mid = (left + right + 1) >> 1;
  5. if (d[mid] <= target) {
  6. left = mid;
  7. } else {
  8. right = mid - 1;
  9. }
  10. }
  11. if (d[left] == target) {
  12. return left;
  13. } else {
  14. return -1;
  15. }
  16. }

Acwing. 790 数的三次方根【浮点数二分】

浮点数二分和整数二分类似,依旧是根据某个条件,把解空间分成两类,通过中点所在的类排除一半的解空间。
浮点数二分边界情况比整数二分要简单。

  1. #include <iostream>
  2. using namespace std;
  3. int main()
  4. {
  5. double n;
  6. cin >> n;
  7. double left = -10000, right = 10000;
  8. while(right - left > 1e-8) {
  9. double mid = (left + right) / 2;
  10. if (mid * mid * mid >= n) {
  11. right = mid;
  12. } else {
  13. left = mid;
  14. }
  15. }
  16. printf("%.6f", right);
  17. return 0;
  18. }