1. 在一个有序数组中找一个数是否存在。
  2. 在一个有序数组中,找>=某个数最左侧的位置。
  3. 局部最小值问题(局部最小:在无序、任意两个相邻的数不相等的数组中,有局部最小定义:如果0位置的数小于1位置的数,那么0称做局部最小,如果位置N-1小于N-2上的数,那么N-1上的数称为局部最小,在相邻的三个数中,中间那个数最小,则这个数叫局部最小。 额好像就是极小值点)。

二分法一般用于有序数组中。

二分法有两种表现形式

34

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
class Solution
{
public:
vector<int> searchRange(vector<int> &nums, int target)
{
int rightBoarder = rightBorder(nums, target);
int leftBoarder = leftBorder(nums, target);
// 情况一
if (leftBoarder == -2 || rightBoarder == -2)
{
return {-1, -1};
}
// 情况二
else if (rightBoarder - leftBoarder > 1)
{
return {leftBoarder + 1, rightBoarder - 1};
}
// 情况三
else
{
return {-1, -1};
}
}
private:
int leftBorder(vector<int> &nums, int target)
{
// 这里可以等于-2,-3,-4等等。
int left = 0, right = nums.size() - 1, leftBoarder = -2;
while (left <= right)
{
int mid = left + ((right - left) >> 1);
if (nums[mid] >= target)
{
right = mid - 1;
leftBoarder = right;
}
else
{
left = mid + 1;
}
}
return leftBoarder;
}
int rightBorder(vector<int> &nums, int target)
{
int left = 0, right = nums.size() - 1, rightBoarder = -2;
while (left <= right)
{
int mid = left + ((right - left) >> 1);
if (nums[mid] <= target)
{
left = mid + 1;
rightBoarder = left;
}
else
{
right = mid - 1;
}
}
return rightBoarder;
}
};

这里主要是分三种情况

  • 情况一:target 在数组范围的右边或者左边,例如数组{3, 4, 5},target为2或者数组{3, 4, 5},target为6,此时应该返回{-1, -1}
  • 情况二:target 在数组范围中,且数组中不存在target,例如数组{3,6,7},target为5,此时应该返回{-1, -1}
  • 情况三:target 在数组范围中,且数组中存在target,例如数组{3,6,7},target为6,此时应该返回{1, 1}

主要把它分成三种情况就好理解了。

69:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Solution {
public:
int mySqrt(int x) {
int left = 1, right = x;
int res = 0;
while (left <= right) {
int mid = left + ((right - left) >> 1);
if (x / mid >= mid) {
res = mid;
left = mid + 1;
} else {
right = mid - 1;
}
}
return res;
}
};

x的平方根可以利用二分法,从一开始,跟二分法差不多。

x / mid >= mid防止栈溢出,别问我怎么知道的,因为我用(mid * mid) <= x的时候给我报栈溢出的错。

只要检测到mid的平方比x小或者等于x的时候就可以将这个值存起来,防止之后的mid变大。

也可以用牛顿迭代法。

367

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Solution {
public:
bool isPerfectSquare(int num) {
int left = 1, right = num;
while (left <= right) {
// 这里用int的话不够准确
// 5 / 2 == 2 显然不对
double mid = left + ((right - left) >> 1);
if (num / mid == mid) {
return true;
} else if (num / mid < mid) {
right = mid - 1;
} else if (num / mid > mid) {
left = mid + 1;
}
}
return false;
}
};

和69题差不多,只是把判断条件细化了,和把mid改用double。

要是不改的话会有误差,因为两个数整除会舍去小数。69题因为找不到平方根的话可以返回一个近似的值,所以可以不用double。

也可以用牛顿迭代法。