文档讲解:代码随想录(programmercarl.com)
视频讲解:手把手带你撕出正确的二分法 | 二分查找法 | 二分搜索法 | LeetCode:704. 二分查找_哔哩哔哩_bilibili数组中移除元素并不容易! | LeetCode:27. 移除元素_哔哩哔哩_bilibili
状态:代码记下了,没太理解
LeeCode 704 二分查找
二分法常用的定义区间包括:左闭右闭[left, right]和 左闭右开[left, right)。首先,左闭右闭[left, right]的C++代码如下:
class Solution {
public:
int search(vector<int>& nums, int val) {
int left = 0;
int right = nums.size() - 1; //有闭区间right可以取到当时的值,所以right需要减1
while(left <= right){ //left==right时区间为[left, right]是合理合法区间
int middle = left+((right-left)/2); //防止溢出
if(nums[middle] > target){ //target处于左区间和middle中间因而更新左区间的右边界
right = middle - 1; //nums[middle>target->middle无需再做判断
} else if (nums[middle] < target){
left = middle - 1; //nums[middle<target->middle无需再做判断
} else { //nums[middle<target
return middle;
}
}
return middle;
}
};
左闭右开[left, right)的C++代码如下:
class Solution {
public:
int search(vector<int>& nums, int target){
int left = 0;
int right = nums.size;
while(left<right){ //left==right时,[left,right)为空区间且不合法
int middle = left + ((right-left)/2);
if(nums[middle] > target){
right = middle; //有开区间middle当时的值未参与判断
} else if (nums[middle] < target){
left = middle + 1; //左闭区间时不变
} else { //nums[middle]==target
return middle;
}
}
return -1;
}
};
两种定义区间下,代码的临界条件是不同的,从上述两段代码中可以看出。
LeeCode 27 移除元素
移除元素:给定一个数组 nums
和一个值 val
, 原地移除所有数值等于 val
的元素,并返回移除后数组的新长度。(不需要考虑数组中超出新长度后面的元素)
不要使用额外的数组空间,你必须仅使用 O(1)
额外空间并原地修改输入数组。
该题目有三种解法:
1. 暴力解法:通过两个嵌套for循环实现,外循环遍历数组元素,内循环更新数组
class Solution {
public:
int removeElement(vector<int>& nums, int val){
int size = nums.size();
for(int i=0;i<size;i++){
if(nums[i]==val){
for(j=i+1;j<size;j++){
nums[j-1]=nums[j];
}
i--; //i以后的数值往前移动了,i也要往前移一位,才能继续判断更新后的下标为i的数组
size--;//数组数值-1
}
}
return size;
}
};
2. 双指针法
通过一个快指针和慢指针在一个for循环下完成两个for循环的工作
- 快指针:寻找新数组的元素,即不含目标元素的数组
- 慢指针:指向新数组下标的位置
双指针算法是一种通过设置两个指针不断进行单向移动来解决问题的算法。最核心的用途是优化时间复杂度,正如上面的暴力解法,它的时间复杂度为O(n^2),通过双指针法将其时间复杂度优化为O(n)。
class Solution {
public:
int removeElement(vector<int>& nums, int val){
int slowIndex = 0;
for(int fastIndex = 0; fastIndex < nums.size(); fastIndex++){
if(val != nums[fastIndex]){
nums[slowIndex] = nums[fastIndex];
}
}
return slowIndex;
}
};
3. 相向双指针法
//改变了元素顺序,确保移动最少元素
class Solution {
public:
int removeElement(vector<int>& nums, int val){
int leftIndex = 0;
int rightIndex = nums.size() - 1;
while(leftIndex <= rightIndex){
//找左边等于val的元素
while(left <= rightIndex && nums[leftIndex] != val){
++leftIndex; //++leftIndex->leftIndex+1, leftIndex=leftIndex+1
}
//找右边不等于val的元素
while(left <= rightIndex && nums[rightIndex] == val){
--rightIndex; //a++和++a两种增量效果相同的情况下,推荐使用后者
}
//将右边不等于val的元素覆盖左边等于val的元素
if(leftIndex < rightIndex) {
nums[leftIndex++] = nums[rightIndex--];
}
}
return leftIndex;
}
};