目录
1.二分查找
class Solution {
public:
int search(vector<int>& nums, int target) {
int left = 0;
int right = nums.size()-1;
while(left <= right)
{
int mid = left + (right - left)/2;
if(nums[mid] > target)
{
right = mid - 1;
}
else if(nums[mid] < target)
{
left = mid + 1;
}
else return mid;
}
return -1;
}
};
当left等于right时也需要判断,因此循环条件是left <= right
朴素二分查找的模板
2.在排序数组中查找元素的第一个和最后一个位置
class Solution {
public:
vector<int> searchRange(vector<int>& nums, int target) {
if(nums.size() == 0)return{-1,-1};
int left = 0;
int right = nums.size()-1;
vector<int> ret(2,-1);
while(left < right)
{
int mid = left + (right - left)/2;
if(nums[mid] < target)
{
left = mid + 1;
}
else right = mid;
}
if(nums[left] == target)ret[0] = left;
else return ret;
left = 0;
right = nums.size()-1;
while(left < right)
{
int mid = left + (right - left + 1)/2;//
if(nums[mid] > target)
{
right = mid - 1;
}
else left = mid;
}
if(nums[right] == target)ret[1] = right;
return ret;
}
};
首先先判断空数组的情况
int mid = left + (right - left)/2;
int mid = left + (right - left + 1)/2;
数组可以被分成两个区块,这里我们以寻找左端点为例子。
数组被分成小于target和大于等于target。
当某一个位置小于target时,这段是必定不可能出现左端点的,因此我们left更新时使用left= mid+1来跳出这个位置。而当这个位置大于等于target时,有可能这个位置就是左端点,right更新时使用right = mid来保留这一位置。
由于这一特性,当我们left等于right的时候,如果此时这个位置的值大于等于target,right的值就会一直保留,无法跳出这一位置,因此我们的循环条件是left < right,在循环结束时判断这一位置是否合法。
同时因为这个特性,当left与right相邻的时候,当left与right对应位置的值均大于等于target的时候,如果我们取 int mid = left + (right - left+1)/2; 此时mid会取到右侧的位置,即right位置,此时会陷入死循环,left与right永远不会相等了。
综上,遇到不跳出原位置的情况我们使用left<right,同时若干不跳出right位置,那么我们取mid时,要取偏左的那位置
3.x的平方根
class Solution {
public:
int mySqrt(int x) {
long long left = 0;
long long right = x;
while(left < right)
{
long long mid = left + (right - left + 1) / 2;
if(mid * mid > x)right = mid - 1;
else left = mid;
}
return left;
}
};
这里循环结束后就是结果了,直接返回即可。考虑到相乘情况太大越界,我们使用longlong
4.搜索插入位置
class Solution {
public:
int searchInsert(vector<int>& nums, int target) {
int left = 0;
int right = nums.size();
while(left < right)
{
int mid = left + (right - left)/2;
if(nums[mid] < target)left = mid + 1;
else right = mid;
}
return left;
}
};
可放置的位置从0下标到nums.size()下标,当left 倒带nums.size()时,left 等于right 循环结束,不会越界,所以循环结束后即为结果。
5.山脉数组的峰顶索引
class Solution {
public:
int peakIndexInMountainArray(vector<int>& nums) {
int left = 0;
int right = nums.size();
while(left < right)
{
int mid = left + (right - left + 1)/2;
if(nums[mid]-nums[mid-1] > 0)left = mid;
else right = mid-1;
}
return left;
}
};
6.寻找峰值
class Solution {
public:
int findPeakElement(vector<int>& nums) {
int left = 0;
int right = nums.size()-1;
while(left < right)
{
int mid = left + (right - left + 1)/2;
if(nums[mid]-nums[mid-1] > 0)left = mid;
else right = mid - 1;
}
return left;
}
};
如果一个位置相较于前一个位置增加,那么该位置及其后面的位置一定有一个是峰值 ,而如果是下降,那么这个位置左侧一定有一个位置是峰值
7.寻找旋转排序数组中的最小值
class Solution {
public:
int findMin(vector<int>& nums) {
int left = 0;
int right = nums.size()-1;
int size = nums.size();
while(left < right)
{
int mid = left + (right - left)/2;
if(nums[mid] > nums[size - 1])left = mid + 1;
else right = mid;
}
return nums[left];
}
};
8.丢失的数字
class Solution {
public:
int missingNumber(vector<int>& nums) {
sort(nums.begin(),nums.end());
int left = 0;
int right = nums.size();
int size = nums.size();
while(left < right)
{
int mid = left + (right - left)/2;
if(nums[mid] == mid)left = mid + 1;
else right = mid;
}
return left;
}
};
需要先把数组排序一下