代码随想录算法训练营第一天| 704. 二分查找、27. 移除元素
LeetCode 704题 二分法查找
题目链接: 704.二分法查找
注:二分法分左闭右闭区间和左闭右开两种写法,在代码中有两点区别,第一点是while判断条件是否取等号,第二点是当target比nums[middle]小,右区间right是否需要对middle-1。
代码实现
写法一:左闭右闭区间
class Solution {
public:
int search(vector<int>& nums, int target) {
//首先获取区间范围
int left = 0;
int right = nums.size()-1;
while(left<=right) { //因为是左闭右闭区间,此处判断条件需要添加等号
int middle = left + (right-left)/2; //与(left+right)/2一样,此操作是为了防止数据溢出
if(nums[middle] > target) {
right = middle - 1; //因为中间数组大于且不等于target,将右区间更新为middle-1
}
else if(nums[middle] < target) {
left = middle + 1; //因为中间数组小于且不等于target,将左区间更新为middle+1
}
else { //当且仅当中间数组等于target
return middle;
}
}
//找不到target
return -1;
}
};
写法二:左闭右开区间
class Solution {
public:
int search(vector<int>& nums, int target) {
//获得数组左右区间值
int left = 0;
int right = nums.size()-1;
while(left < right) { //此处不能取等号
int middle = left + (right - left)/2;
if(nums[middle] > target) { //当中间数组大于target
right = middle; //此处right不能取middle-1,右区间为开区间
}
else if(nums[middle] < target) { //当中间数组小于target
left = middle + 1; //将左区间left更新为middle+1
}
else { //当且仅当中间数组等于target
return middle;
}
}
//找不到target
return -1;
}
};
本题小结
二分查找有两种写法(左闭右闭,左闭右开),其使用条件为数组为有序数组且数组中无重复元素,代码中需要注意边界条件的判断。
LeetCode 27题 移除元素
题目链接: 27.移除元素
思路:该题第一想法可用暴力解法,使用两个for循环覆盖数组中的val
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) { //找到数组中的val值
for(int j = i + 1; j < size; j++) { //利用数组中该值后面的值将其覆盖
nums[j-1] = nums[j];
}
i--; //因为小标整体向前移动了1位,i也需要向前移动1位
size--; //数组大小-1
}
}
return size;
}
};
注:数组在地址上是连续的,无法进行删除,只能将其覆盖。
此解法算法复杂度为O(n^2),且在覆盖之后容易忘记将数组下标i减1。
同向双指针法(快慢指针):通过快指针和慢指针在一个for循环代替两个for循环
快指针寻找新元素,慢指针更新下标
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]) { //当且仅当快指针指向的元素值不等于val
nums[slowIndex++] = nums[fastIndex]; //使用慢指针指向的元素将原数组覆盖
}
}
return slowIndex;
}
};
注:此方法时间复杂度为O(n),但是该方法没有改变元素的相对位置。
相向双指针法,基于元素顺序可以改变的题目描述改变了元素相对位置,确保移动最少元素。
思路:
class Solution {
public:
int removeElement(vector<int>& nums, int val) {
//定义相向指针
int leftIndex = 0;
int rightIndex = nums.size()-1;
while(leftIndex <= rightIndex) {
//寻找左边等于val的元素
while(leftIndex <= rightIndex && nums[leftIndex] != val) {
leftIndex++;
}
//寻找右边不等于val的元素
while(leftIndex <= rightIndex && nums[rightIndex] == val) {
rightIndex--;
}
//将右边不等于val的元素覆盖左边等于val的元素
if(leftIndex < rightIndex) {
nums[leftIndex++] = nums[rightIndex--];
}
}
return leftIndex; //此时leftIndex一定指向数组末尾的下一个元素,即数组大小
}
};
注:此方法时间复杂度也为O(n)