文章目录
一、总览
二、完全有序的二分查找
2.1 原始二分查找
https://leetcode-cn.com/problems/search-insert-position/
解题:这道题是最原始的二分查找,时间复杂度O(logn)
,注意边界条件:low <= high
class Solution {
public:
int searchInsert(vector<int>& nums, int target)
{
int low = 0, high = nums.size() - 1;
while (low <= high)
{
int mid = low + (high - low) / 2;
if (nums[mid] == target)
return mid;
else if (nums[mid] < target)
low = mid + 1;
else
high = mid - 1;
}
return low;
}
};
2.2 寻找第一个等于元素的位置
https://leetcode-cn.com/problems/find-first-and-last-position-of-element-in-sorted-array/
解题:这个题可用原始二分查找,只需要加上判断是不是第一个位置的条件,如果不是则high = mid - 1
class Solution {
public:
int searchFirst(vector<int>& nums, int target)
{
int low = 0, high = nums.size() - 1;
while (low <= high)
{
int mid = low + (high - low) / 2;
if (nums[mid] == target)
{
if(mid == 0 || nums[mid - 1] != target)
return mid;
high = mid - 1;
}
else if (nums[mid] < target)
low = mid + 1;
else
high = mid - 1;
}
return -1;
}
};
2.3 寻找最后一个等于元素的位置
https://leetcode-cn.com/problems/find-first-and-last-position-of-element-in-sorted-array/
解题:和找第一个相等位置相同,只要改下判断nums[mid] == target
时的逻辑
class Solution {
public:
int searchLast(vector<int>& nums, int target)
{
int low = 0, high = nums.size() - 1;
while (low <= high)
{
int mid = low + (high - low) / 2;
if (nums[mid] == target)
{
if(mid == nums.size() || nums[mid + 1] != target)
return mid;
low = mid + 1;
}
else if (nums[mid] < target)
low = mid + 1;
else
high = mid - 1;
}
return -1;
}
};
2.4 寻找第一个大于元素的位置
class Solution {
public:
int BinSearch(vector<int>& nums, int target)
{
int left = 0, right = nums.size() - 1;
while (left <= right)
{
int mid = left + (right - left) / 2;
if (nums[mid] <= target)
// 说明第一个大于tar的元素在[mid+1, right]区间
left = mid + 1;
else
// [mid, right]区间的元素都比tar大
right = mid - 1;
}
// 二分查找结束之后,left的元素一定是大于tar的第一个元素
if (left < nums.size())
return left;
return -1; // 到这,说明target比数组中的所有数都大
}
};
2.5 寻找第一个小于元素的位置
class Solution {
public:
int BinSearch(vector<int>& nums, int target)
{
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;
}
// 二分查找结束之后,right的元素一定是小于tar的第一个元素
if (right >= 0)
return right;
return -1; // 到这,说明target比数组中的所有数都小
}
};
三、不完全有序的二分查找
3.1 搜索旋转排序数组
https://leetcode-cn.com/problems/search-in-rotated-sorted-array/
class Solution {
public:
int search(vector<int>& nums, int target)
{
// 二分法:找递增的区间
// 如果[left, mid]区间是递增的,则target需要和nums[left]比较,划分区间
// 如果[mid + 1, right]区间是递增的,则target需要和nums[right]比较划分区间
int left = 0, right = nums.size() - 1;
while (left <= right) // 这里注意left <= right
{
int mid = left + (right - left) / 2;
if (nums[mid] == target)
return mid;
if (nums[mid] >= nums[left]) // 左边区间是递增的
{
if (target >= nums[left] && target < nums[mid])
right = mid - 1;
else
left = mid + 1;
}
else // 右边区间是递增的
{
if (target <= nums[right] && target > nums[mid])
left = mid + 1;
else
right = mid - 1;
}
}
return -1;
}
};
3.2 搜索旋转排序数组II (元素可能重复)
https://leetcode-cn.com/problems/search-in-rotated-sorted-array-ii/
class Solution {
public:
bool search(vector<int>& nums, int target)
{
if (nums.size() == 0)
return false;
int low = 0, high = nums.size() - 1;
while(low <= high)
{
int mid = low + (high - low) / 2;
if(nums[mid] == target)
return true;
else if(nums[mid] > nums[low])
{
if(nums[low] <= target && target < nums[mid])
high = mid - 1;
else
low = mid + 1;
}
else if(nums[mid] < nums[high])
{
if(nums[mid] < target && target <= nums[high])
low = mid + 1;
else
high = mid - 1;
}
else
{
if(nums[low] == nums[mid])
low++;
if(nums[high] == nums[mid])
high--;
}
}
return false;
}
};
3.3 寻找旋转排序数组中的最小值
https://leetcode-cn.com/problems/find-minimum-in-rotated-sorted-array/
class Solution {
public:
int findMin(vector<int>& nums) {
if(nums.empty()) return -1;
if(nums.size() == 1) return nums[0];
int p1 = 0, p2 = nums.size() - 1;
int mid = p1; // 假如旋转了数组的前面0个元素(也就是没有旋转),我们直接返回numbers[p1]
while(nums[p1] > nums[p2])
{
if(p2 - p1 == 1)
{
// 循环终止条件:当p2-p1=1时,p2所指元素为最小值
mid = p2;
break;
}
mid = p1 + (p2 - p1) / 2;
if(nums[mid] > nums[p1]) p1 = mid;
else p2 = mid;
}
return nums[mid];
}
};
3.4 寻找旋转排序数组中的最小值II (元素可能重复)
https://leetcode-cn.com/problems/find-minimum-in-rotated-sorted-array-ii/
class Solution {
public:
int findMin(vector<int>& nums)
{
int low = 0, high = nums.size() - 1;
while(low < high)
{
if(nums[low] < nums[high])
return nums[low];
int mid = low + ((high - low) >> 1);
if(nums[mid] > nums[low])
low = mid + 1;
else if(nums[mid] < nums[low])
high = mid;
else
low++;
}
return nums[low];
}
};