文章

算法初步-二分查找

算法初步-二分查找

Binary Search

SQUINT - 整数平方根

问题描述

给定一个整数 $n$,求最小的非负整数 $r$,使得 $r^2 \geq n$(即 $\lceil \sqrt{n} \rceil$)。

样例

| 输入 | 输出 | |:—:|:—:| | 122333444455555 | 11060446 |

验证:

  • $11060445^2 = 122333443598025 < 122333444455555$ ❌
  • $11060446^2 = 122333465718916 \geq 122333444455555$ ✓
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
// 定义 long long 类型的简写,方便后续使用
typedef long long ll;

// 函数声明:计算整数平方根(向上取整)
// 参数 a: 输入的非负整数
// 返回值: 满足 r^2 >= a 的最小非负整数 r
long long squint(long long a);

int main() {
  // 关闭 C++ 流与 C 流的同步,提高输入输出效率
  ios::sync_with_stdio(false);
  // 解除 cin 与 cout 的绑定,进一步提升输入输出速度
  cin.tie(nullptr);

  long long a;      // 定义变量存储输入的整数
  cin >> a;         // 从标准输入读取整数

  cout << squint(a); // 调用 squint 函数并输出结果

  return 0;         // 程序正常结束
}

/**
 * 二分查找算法实现整数平方根
 * 
 * 算法思想:
 * 1. 在区间 [1, a] 中查找满足条件的值
 * 2. 对于中间值 mid,比较 mid^2 与 a 的大小
 * 3. 为避免 mid * mid 溢出,使用 mid <= a / mid 进行判断
 * 4. 最终返回满足 r^2 >= a 的最小 r
 */
long long squint(long long a) {
  // 定义二分查找的左右边界
  // left: 查找区间的左端点,初始值为 1
  // right: 查找区间的右端点,初始值为 a
  ll left = 1, right = a;
  
  // ans 用于存储当前找到的答案,初始化为 a(最坏情况下答案就是 a 本身)
  ll ans = a;

  // 二分查找的主循环,当左边界不超过右边界时继续查找
  while (left <= right) {
    // 计算中间位置,使用 left + (right - left) / 2 而非 (left + right) / 2
    // 目的是防止 left + right 可能导致的整数溢出
    ll mid = left + (right - left) / 2;

    // 判断条件:mid^2 <= a 等价于 mid <= a / mid(避免溢出)
    // 如果 mid 的平方小于等于 a,说明 mid 可能是答案,但还需要尝试更大的值
    if (mid <= a / mid) {
      // 将左边界右移,继续在右半区间查找是否存在更大的满足条件的值
      left = mid + 1;
    } else {
      // mid 的平方大于 a,说明 mid 太大,需要在左半区间查找更小的值
      right = mid - 1;
    }
    // 更新答案为当前的 mid
    // 注意:这里 ans 可能保存的是不满足条件的值,需要在循环后修正
    ans = mid;
  }

  // 循环结束后,需要验证 ans 是否真正满足 ans^2 >= a
  // 如果不满足(即 ans^2 < a),则将 ans 加 1
  // 这是因为二分查找过程中 ans 可能保存的是最后一个 mid <= a / mid 的值
  if (ans * ans < a) {
    ans += 1;
  }
  return ans;  // 返回最终的整数平方根(向上取整)
}
本文由作者按照 CC BY 4.0 进行授权

热门标签