整数二分查找算法思路总结:
1、整数二分算法一定有解,但是需要检查解是不是所需要的解
2、整数二分可以分为两种区间范围:
左闭右闭(常用,mid>=target):
/*定义左区间*/
l = 0
/*定义右区间*/
r = nums.size()-1
左闭右开(mid>target)
/*定义左区间*/
l = 0
/*定义右区间*/
r = nums.size()
3、整数二分步骤:
步骤1:定义左右区间(常用左闭右闭)
int l = 0;
int r = nums.size()-1;
步骤2:开始循环二分,直到l>=r停下
while(l<r)
{
...
}
步骤3:在循环中定义中点位置,并进行中点位置与target的判断,更新端点
int l = 0;
int r = nums.size()-1;
while(l<r)
{
//方式1:
int mid =(l+r)>>1;
if(nums[mid]>=target)
{
r = mid;
}
else
{
l = mid+1;
}
}
方式1是在当target的位置在mid的左边满足true时使用,比如寻找非递减数组中的某个元素的第一个值的位置,需要满足mid的位置>=第一个值的位置。
如果在此时使用mid=(l+r+1)>>1,会出现无限循环,假设[3,3],需要第一个值的位置, mid = (0+1+1)>>1=1;(nums[1]=3)>=(target=3);r=mid=1,与上一次一样,就会无限循环。
int l = 0;
int r = nums.size()-1;
while(l<r)
{
//方式2:
int mid =(l+r+1)>>1;
if(nums[mid]<=target)
{
l = mid;
}
else
{
r = mid-1;
}
}
方式2是在当target的位置在mid的右边满足true时使用,比如寻找非递减数组中的某个元素的最后一个值的位置,需要满足mid的位置<=最后一个值的位置。
如果在此时使用mid=(l+r)>>1,会出现无限循环,假设[3,3],需要最后值的位置, mid = (0+1)>>1=0;(nums[0]=3)<=(target=3);l=mid=0,与上一次一样,就会无限循环。
LeetCode704 二分查找
题目链接:704.二分查找
class Solution {
public:
int search(vector<int>& nums, int target) {
//定义左右下标,使用左闭右闭
int l=0,r= nums.size()-1;
//判断什么时候可以找到target
while(l<r)
{
//定义中点位置
//1、如果中点位置满足nums[mid]>=target返回true时,中点位置使用mid = (l+r)>>1
//2、如果中点位置满足nums[mid]<=target返回true时,中点位置使用mid = (l+r+1)>>1
int mid = l+r>>1;
if(nums[mid]>=target) r = mid;
else l=mid+1;
}
return nums[l]==target?l:-1;
}
};
LeetCode35 搜索插入位置
题目链接:35.搜索插入位置
class Solution {
public:
int searchInsert(vector<int>& nums, int target) {
//排序数组,本身满足二分法
//定义左右闭区间
int l=0,r=nums.size()-1;
//如果大于整个数组:
if(target>*(nums.end()-1))return nums.size();
//二分循环判断
while(l<r)
{
//定义中点,两种方式都行,这里使用nums[mid]>=target,r= mid
int mid = l+r>>1;
if(nums[mid]>=target) r = mid;
else l=mid+1;
}
//4,6找5,l=0,r=1,mid=0,nums[mid]=4<5,触发l =0+1=1,满足要插入的位置
return nums[l]==target?l:l;
}
};
问题:
1、在普通的二分法基础上,增加了另外的判断情况,如果不存在需要返回插入位置,所以就会出现如果target>nums的最大值,需要将其插入到最后。
LeetCode34 在排序数组中查找元素的第一个和最后一个的位置
class Solution {
public:
vector<int> searchRange(vector<int>& nums, int target) {
//使用两个二分法,分别查找左右位置
//左边的起始位置满足:nums[mid]>=target,
//右边的最终位置满足:nums[mid]<=target
int l=0,r=nums.size()-1;
int i=l,j=r,m=l,n=r;
vector <int>res(2,-1);
if(!nums.size()) return res;
while(i<j)
{
int mid = (i+j)>>1;
if(nums[mid]>=target) j = mid;
else i=mid+1;
}
if(nums[i]==target)
{
res[0]=i;
while(m<n)
{
int mid = m+n+1>>1;
if(nums[mid]<=target) m=mid;
else n=mid-1;
}
res[1]=m;
}
return res;
}
};
问题:
1、需要使用两次二分来寻找左右两个值,nums[mid]>=target,可以用于寻找第一个元素,nums[mid]<=target,可以用于寻找最后一个元素
2、判断当nums.size()==0时的情况
移除数组中的某些元素思路总结:
1、快慢指针:快慢指针在同一个for循环下工作,慢指针用于记录新的数组,快指针用于遍历数组
2、左右指针:左右指针向中间逼近,左指针、右指针分别寻找满足自己的条件,然后在满足l<r条件下,swap(左指针,右指针)
LeetCode27 移除元素
题目链接:27、移除元素
class Solution {
public:
int removeElement(vector<int>& nums, int val) {
//使用左右指针
//左指针找到val停下
//右指针找到不是val的停下
//左右指针swap
int left=0,right=nums.size()-1;
while(left<right)
{
while(nums[left]!=val&&left<right) left++;
while(nums[right]==val&&left<right) right--;
if(left<right)
{
swap(nums[left],nums[right]);
left++;
right--;
}
}
int i=0;
for(i;i<nums.size();i++)
{
if(nums[i]==val) break;
}
return i;
}
};
class Solution {
public:
int removeElement(vector<int>& nums, int val) {
//快慢指针
int slow=0;
for(int fast=0;fast<nums.size();fast++)
{
if(nums[fast]!=val) nums[slow++]=nums[fast];
}
return slow;
}
};
LeetCode26 删除有序数组中的重复项
题目链接:26、删除有序数组中的重复项
class Solution {
public:
int removeDuplicates(vector<int>& nums) {
//使用快慢指针
//slow指针记录新数组
//fast指针遍历全部的数组
if(!nums.size())return 0;
int slow=0;
for(int fast = 0;fast<nums.size();fast++)
{
if(nums[fast]!=nums[slow])
{
nums[++slow] = nums[fast];
}
}
//最终要的时元素数量,所以要+1
return slow+1;
}
};
LeetCode283 移动0
题目链接:283、移动0
class Solution {
public:
void moveZeroes(vector<int>& nums) {
//使用快慢指针
//不易使用左右指针,因为这个题需要保持非零元素的相对顺序
int slow=0;
for(int fast=0;fast<nums.size();fast++)
{
//如果发现快指针不为0,交换
if(nums[fast]!=0)
{
swap(nums[slow++],nums[fast]);
}
}
}
};
LeetCode977 有序数组的平方
题目链接:有序数组的平方
class Solution {
public:
vector<int> sortedSquares(vector<int>& nums) {
//左右指针,向中间逼近
//左右相等的时候也要进行填入
int left=0,right=nums.size()-1;
vector <int> res;
while(left<=right)
{
if(nums[left]*nums[left]<=nums[right]*nums[right])
{
res.push_back(nums[right]*nums[right]);
right--;
}
else
{
res.push_back(nums[left]*nums[left]);
left++;
}
}
//输入的顺序是从大到小,需要reverse
reverse(res.begin(),res.end());
return res;
}
};
思路:
1、使用双指针,从两边向中间夹进,但是当左右相等的时候,也需要进行填入
2、首先输入的是最大元素,而题目要求是从小到大,所以需要翻转vector,reverse