代码随想录算法训练营
Day1 代码随想录算法训练营第一天 |LeetCode704. 二分查找、LeetCode35.搜索插入位置、Leetcode27. 移除元素
目录
前言
备战期末工科数学分析刷题打卡
今天是算法训练营第一天,主要学习的是二分查找和快慢指针
LeetCode704
LeetCode27
一、LeetCode704. 二分查找
题目链接:LeetCode704
1.基础
(1)二分查找的条件:有序数组
(2)二分查找的时间复杂度 o(logn)
2.二分查找的两种写法
左闭右闭区间[l,r] | 左闭右开区间[l,r) | |
---|---|---|
遍历边界 | l<=r | l<r |
遍历边界的解释 | 当l=r时,区间[l,r]有意义,还可以继续求mid | 在l=r时,区间[l,r]无意义,不可以继续求mid |
r和l的更新 | l=mid+1,r=mid-1 | l==mid+1,r=mid |
r和l的更新的解释 | 无论nums[mid]>target还是nums[mid]<target,mid对应的值都不是我们要找的目标,不该出现在备选区间 | nums[mid]>target或者nums[mid]<target,mid不该出现在备选区间,但是备选区间不包含r,所以mid为r是可以的 |
3.二分搜索
在了解二分查找的本质后,我们用同样的办法确定二分搜索问题的边界和更新方式
3.题解
(个人喜欢左闭右闭区间,暂时就写了这一种(/ω\))
class Solution {
public:
int search(vector<int>& nums, int target) {
int l = 0;
int n = nums.size();
int r = n - 1;
int mid;
while (l <= r) {
mid = (l + r) / 2;
if (nums[mid] < target) {
l = mid + 1;
} else if (nums[mid] > target) {
r = mid - 1;
} else {
return mid;
}
}
return -1;
}
};
二、LeetCode35.搜索插入位置
1.我的题解
class Solution {
public:
int searchInsert(vector<int>& nums, int target) {
int l = 0;
int n = nums.size();
int r = n - 1;
int res;
int mid;
while (l < r) {
mid = (l + r) / 2;
if (nums[mid] > target) {
r = mid - 1;
} else if (nums[mid] < target) {
l = mid + 1;
} else {
l = mid;
r = mid;
break;
}
}
if (nums[l] < target) {
return l + 1;
} else {
return l;
}
}
};
2.想法
(1)查找方式:
题目要求时间复杂度o(logn),所以用二分查找(我在这里用的是左闭右闭区间写法)
(2)哪里和模板不一样:
现在我们不是要找到和target 相等的元素,我们要找插入位置,不一定有和target相等的元素
(3)初步判定有两种主要情况
1)存在和target相等的元素:
target插在这个和他相等的元素所在的位置,也就是一开始和他相等的元素及其后边的元素应当向右移动
这个时候可以break出来,在外面return。
为什么把l,r赋值成mid:这种情况下不能确定l=mid,为了统一循环后面的返回部分所以这样写
(一开始这里出错了)
2)不存在和target相等的元素:
r与l不断接近,达到相等,最后退出循环。如果要确定target插入位置,应该在l=r时确定,所以循环边界设定为l<r,这样在l=r时可以退出循环,进入插入位置的判别。
l=r时可以分为两种,若target大于此时nums[l],则插在l+1的位置;若target小于此时nums[l],则插在l的位置,相当于nums[l+1]元素及其后边的元素应当向右移动
三、Leetcode27. 移除元素
1.快慢指针法
快指针i:负责遍历原数组,判断元素与val是否一致
慢指针j:负责遍历新数组,指向新数组最新的一个元素
2.想法
(1)快指针i负责遍历原数组,判断元素与val是否一致
如果一致,则更新快指针而慢指针不动;
如果一致,则慢指针指向这个元素(nums[j]=nums[i]),更新快指针和慢指针
(2)节约空间
新数组仍然利用nums的空间,快指针找到不同于val的元素后,慢指针将他保存到新的nums里,覆盖掉原来的val,依次存放,确保顺序不变
为什么可行:判题时只看前k个元素,确保前k个元素是不含val的,按照原顺序排列的即可
3我的题解
class Solution {
public:
int removeElement(vector<int>& nums, int val) {
int n = nums.size();
int j = 0;
for (int i = 0; i < n; i++) {
if (nums[i] != val) {
nums[j] = nums[i];
j++;
}
}
return j++;
}
};
4曾经的做法
这种做法是先从先向后遍历,如果遇到等于val的元素,就从这一点开始将后一个元素赋给前一个元素(整体向左移动)。
元素前移:这是数组删除元素的一般方法,但是在这里其实没有必要这样做。
class Solution {
public:
int removeElement(vector<int>& nums, int val) {
int n=nums.size();
int i=0;
while(i<n){
if(nums[i]!=val){
i++;
continue;
}
else{
for(int k=i;k<=n-2;k++){
nums[k]=nums[k+1];
}
n--;
}
}
return n;
}
};
总结
今天是算法训练营第一天,主要学习的是二分查找和快慢指针
快慢指针一些更重要的用途可能明天会做。
希望这个暑假算法水平能有进步(╹▽╹)