2021.12.9 星期四
NO.704 二分查找
看到有序数组,就可以判断可不可以用二分法。
注意对区间的定义:
1.[lo,hi] 左右都闭
再做一遍,发现会出现else if 和else这里的问题,注意多个if和else在一起时的逻辑关系。
class Solution {
public:
int search(vector<int>& nums, int target) {
int lo,hi,mid;
lo=0,hi=nums.size()-1,mid=0;
while(lo<=hi){
int mid=lo+(hi-lo)/2;
if(nums[mid]<target) lo=mid+1;
else if(target<nums[mid]) hi=mid-1;
else return mid;
}
return -1;
}
};
2.[lo,hi) 左闭右开
class Solution {
public:
int search(vector<int>& nums, int target) {
int lo,hi,mid;
lo=0,hi=nums.size()-1,mid=0;
while(lo<hi){
int mid=lo+(hi-lo)/2;
if(nums[mid]<target) lo=mid+1; //说明target在右区间[mid,hi)
else if(target<nums[mid]) hi=mid; //说明target在左区间 [lo,mid)
else return mid;
}
return -1;
}
};
NO.35 搜索插入位置
方法一-二分查找
class Solution {
public:
int searchInsert(vector<int>& nums, int target) {
int lo,hi,mid;
lo=0;
hi=nums.size()-1;
while(lo<=hi){
mid=lo+(hi-lo)/2;
if(nums[mid]<target) lo=mid+1;
else if(target<nums[mid]) hi=mid-1;
else return mid;
}
return lo; //lo 或者 hi-1 都可以
}
};
方法二-暴力解法方法
class Solution {
public:
int searchInsert(vector<int>& nums, int target) {
for(int i=0;i<nums.size();i++){
if(nums[i]>=target) return i;//一旦看到大于target,那么这个i就是我们的返回值
}
return nums.size(); //循环结束还没有返回值,说明所有的元素都比target小,因此插在末尾
}
};
NO.34 有序数组中查找目标的第一和最后一个位置
跟着代码随想录的方法:
方法一-把找左右边界分开
class Solution {
public:
vector<int> searchRange(vector<int>& nums, int target) {
int Right=getRight(nums,target);
int Left=getLeft(nums,target);
if(Right==-2||Left==-2) return {-1,-1};
if(Right-Left>=2) return{Left+1,Right-1};
return {-1,-1};
}
private:
int getRight(vector<int>& nums, int target){
int lo,hi,mid,Right;
lo=0,hi=nums.size()-1,mid=0;
Right=-2; //Right初始不能初始化为-1,因为返回值可能是-1
while(lo<=hi){
mid=lo+(hi-lo)/2;
if(nums[mid]<=target) {
lo=mid+1; //target在右区间上,[mid+1,hi]上
Right=lo; }//当找到了target之后,lo会不断增加,直到增加到比target大的数,就转到了hi减小,直到循环停止,此时lo由于是边界,所以循环停止时的lo的位置应该是不包括target值的右边界
else hi=mid-1;
}
return Right;
}
int getLeft(vector<int>& nums, int target){
int lo,hi,mid,Left;
lo=0,hi=nums.size()-1,mid=0;
Left=-2;//left初始不能初始化为-1,因为返回值可能是-1
while(lo<=hi){
mid=lo+(hi-lo)/2;
if(nums[mid]<target) lo=mid+1;
else { //target在左区间上,[lo,mid-1]上
hi=mid-1;
Left=hi;} //当找到了target之后,hi会不断变小,直到减小到比target小的数,转到了lo且lo开始变大,直到循环停止,此时hi的最终值应该是左边界且不包含target
}
return Left;
}
};
方法二-左右放在一起
实质上还是一样的
class Solution {
public:
vector<int> searchRange(vector<int>& nums, int target) {
if (nums.size()<1) return {-1,-1};
int l=0,h=nums.size()-1,mid;
int m=0,n=nums.size()-1;
//找左边界
while(l<=h){
mid=l+(h-l)/2;
nums[mid]<=target?l=mid+1:h=mid-1;
}
//找右边界
while(m<=n){
mid=m+(n-m)/2;
target<=nums[mid]?n=mid-1:m=mid+1;
}
//l是右边界,n是左边界
if(nums[l-1]==target&&nums[n+1]==target) return {n+1,l-1};
else return {-1,-1};
}
};
2021.12.14
NO.27 移除元素
双指针法:
class Solution {
public:
int removeElement(vector<int>& nums, int val) {
int i=0; //找到同样的就停下
for(int j=0;j<nums.size();j++){
if(nums[j]!=val){
nums[i++]=nums[j];
}
}
return i;
}
};
NO.26 删除重复元素
class Solution {
public:
int removeElement(vector<int>& nums, int val) {
int i=0; //找到同样的就停下
for(int j=0;j<nums.size();j++){
if(nums[j]!=val){
nums[i++]=nums[j];
}
}
return i;
}
};
NO.283 移动零 √
2021.12.18 星期六
NO.977 有序数组的平方
双指针法,用归并的思路处理!
NO.209 长度最小子数组
移动窗口法
2021.12.20 星期一
螺旋矩阵 至此数组部分暂时告一段落