二分查找实际上是一棵二叉递归树,每次进行一半的剪枝,是不是就明白了?原来二分查找对应的数据结构是二叉树,那么二分查找的时间复杂度就是树高 。
原理:把原序列划分成元素个数尽量相同的两个子序列,然后递归查找(但一般写成非递归的 )。
二分查找适用于有序序列。
方法一
最经典:查找的是全部 target 中的其中一个
bool binarySearch(vector<int>& arr, int target){
if(arr.size() == 0) return false;
int left = 0, right = arr.size() - 1;
while(left <= right){
int mid = left + (right - left) / 2;
// mid = (left + right) / 2 会越界!
if(arr[mid] > target) right = mid - 1;
else if(arr[mid] < target) left = mid + 1;
else{
return true;
}
}
// left > right 结束 while
return false;
查找等于 target 的第一个元素下标,即查找 target 左边界。
int binarySearch(vector<int>& nums, int target){
if(nums.size() == 0)
return -1;
int left = 0, right = nums.size() - 1;
while(left <= right) {
int mid = left + (right - left) / 2;
if(nums[mid] < target) {
left = mid + 1;
} else {
right = mid - 1;
}
}
if (left != nums.size() && nums[left] == target) return left;
return -1;
}
查找等于 target 的最后一个元素下标,即查找 target 右边界。
int binarySearch(vector<int>& nums, int target){
if(nums.size() == 0)
return -1;
int left = 0, right = nums.size() - 1;
while(left <= right) {
int mid = left + (right - left) / 2;
if(nums[mid] <= target) {
left = mid + 1;
} else {
right = mid - 1;
}
}
if (right != -1 && nums[right] == target) return right;
return -1;
方法二
还有另一种更简单的方法求左边界和右边界:
查找左边界
// q[] 为有序数组,x 为要查询的数
int bsearch_1(int l, int r)
{
while (l < r)
{
int mid = l + r >> 1;
if (q[mid] >= x) r = mid;
else l = mid + 1;
}
return l;
}
查找右边界
int bsearch_2(int l, int r)
{
while (l < r)
{
int mid = l + r + 1 >> 1; // 注意 +1,否则会进入死循环
if (q[mid] <= x) l = mid;
else r = mid - 1;
}
return l;
}
示例
相当于在 j + 1 到 n 中找第三条边的右端点。如果找不到,此时 left = n + 1,所以二分之后给了一个判断。
class Solution {
public:
int triangleNumber(vector<int>& nums) {
int n = nums.size();
sort(nums.begin(), nums.end());
int res = 0;
for (int i = 0; i < n; i++) {
for (int j = i + 1; j < n; j++) {
int left = j + 1, right = n - 1;
while (left < right) {
int mid = (left + right + 1) >> 1;
if (nums[mid] < nums[i] + nums[j]) left = mid;
else right = mid - 1;
}
if (left != n && nums[i] + nums[j] > nums[left]) res += left - j; // left <= n
}
}
return res;
}
};