代码随想录算法训练营第一天 | Leetcode704.二分查找、27.移除元素
前言
本文将分享自己学习二分查找和移除元素的经验
一、LeetCode704二分查找
接下来我先写出二分的常用的模板,考虑到整数二分的情况比较复杂,所以接下来只列举整数二分,这又会分为两种情况,总的可以概括为:数组区间为左闭右闭和左闭右开。
划重点:模板还是很重要的,一定要记住,多背过几遍
1.左闭右闭代码如下
//区间划[l,r]划分为[l,mid]和[mid + 1,r]时使用
int sreach(int l,int r)
{
while(l <= r)
{
int mid = (l + r)>>1;//如果害怕越界可以改成 l + (l-r)>>1;
if(check(mid)) r = mid-1;//check()判断mid是否满足性质,目标在左半部分的话修改右边界,否则修改左边界
else l= mid + 1;
}
}
2.左闭右开代码如下
//区间划[l,r]划分为[l,mid]和[mid + 1,r]时使用
int sreach(int l,int r)
{
while(l < r)
{
int mid = (l + r)>>1;
if(check(mid)) r = mid;//check()判断mid是否满足性质,目标在左班部分的话修改右边界,否则修改左边界,因为mid值已经被访问,而该方法又取不到右边界,而之后又要用到递归,所以要这样写
else = mid + 1;
}
}
二、LeetCode704
思路:1.看左闭右闭还是左闭又开的情况。
2.分辨出我们要用到的check()方法的具体含义
3.套模板
4.题目的额外要求
分析:1.本题目为左闭右闭的情况.
2.check()方法的具体表示为nums[mid]与target的大小的比较.
3.套模板.
4.题目额外要求为没查到时返回-1.
1.Java
代码如下
class Solution {
public int search(int[] nums, int target) {
//这里的 l 和 f自己进行初始化
int left = 0;
int right = nums.length -1;
//模板,情形为左闭右闭。判断条件check()是和目标值比较大小。
while(left <= right) {
int mid = (left + right)>>1;
if(nums[mid]==target)
return mid;
else if(nums[mid] > target)
right = mid-1;
else
left = mid +1;
}
return -1;
}
}
2.C++
代码如下
class Solution {
public:
int search(vector<int>& nums, int target) {
int left = 0;
int right = nums.size() -1;
//模板开始,左闭又闭,check类型:比较大小,nums[mid]和target的关系
while(left <= right) {
int mid = (left + right)>>1;
if(nums[mid]==target)
return mid;
else if(nums[mid] > target)
right = mid-1;
else
left = mid +1;
}
return -1;
}
};
这里其实JAVA和C+++其实并没有特别大的区别。要注意JAVA中int right = nums.length -1;和C++中的int right = nums.size() -1;的不同。其它的思想是一致。
总结且思考:二分不只是可以查找一些数,它本质是对一些性质的筛选。在LeetCode702中,它代表的性质刚好就是数字大小的性质。实际上,其他性质也同样适用于二分查找,从而我们也可以得出一个结论:二分查找不一定需要有单调性,没有单调性也同样可以用二分。
三.LeetCode 27.移除元素
1.简单介绍:双指针法最大的用处使用来优化,原来的暴力解法两个for循环的时间复杂度是O(n平方),利用双指针可以缩小到O(n).所以思考时,我可能可以先考虑写出暴力解法,然后寻找 i 和 j 的线性关系。随后在进行优化处理
对于本题目,我们双指针一先一后,先指针fast用来记录新数组将要获得的元素,而后指针slow用来记录新数组元素将要存放的地址:
思路:1.遍历,找出需要移除的元素位置。**替换:从数组的后面寻找元素替换。1)当前数组最后一个元素仍需要移除则更新数组元素后继续前移。2)当最后一个数组不需要移除,那就进行替换
2.更新数组的长度,继续遍历
以下是一个双指针的小模板
2.Java
代码如下
class Solution {
public int removeElement(int[] nums, int val) {
int slow = 0;
for(int fast = 0;fast < nums.length - 1;fast++){
if(nums[fast] != val){//不需要删除的情况.更新数组
nums[slow] = nums[fast];//快指针用来获取新获得的元素,慢指针用来获取新数组中的地址
slow++;//位置同样往后移动
}
}
return slow;
}
}
3.C++
代码如下
class Solution {
public:
int removeElement(vector<int>& nums, int val) {
int slow = 0;
for(int fast = 0;fast < nums.size() - 1;fast++){
if(nums[fast] != val){//不需要删除的情况.更新数组
nums[slow] = nums[fast];//快指针用来获取新获得的元素,慢指针用来获取新数组中的地址
slow++;//位置同样往后移动
}
}
return slow;
}
};