算法第1天|704 二分查找、27 去除元素
*简介:记录一刷算法存在的问题和解题思想,养成每日学习总结的习惯
704:二分查找
题目链接
提示:由于数组元素有序且可以假定不重复,因此想到使用二分查找;
二分查找的关键:
- 能想到用二分查找来解决;
- 根据区间的定义确定判断条件是否需要等号,新的区间是否要+1 or -1.(闭1)
/*
存在的问题:
1.循环的结束条件
2.没有考虑左闭右闭or左闭右开
3.left right的初始化
4.未考虑left+right可能会溢出的问题
*/
class Solution {
public:
int search(vector<int>& nums, int target) {
int middle = nums.size()/2
while(){
if(traget < right)
right = middle;
else if (target > left)
left = middle;
else
return middle;
}
return -1;
}
};
正解
左闭右闭:
/*用时3ms*/
1.循环的结束条件:即二分查找条件,查找范围不为空
2.溢出问题:若数组长度较大,计算中点操作(left+right)/2 中的left+right可能超出int类型的取值范围,从而导致计算错误。此时,需使用(right-left)/2+left计算中点,避免此问题。
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 (target < nums[middle]){
right = middle - 1;
} else if (nums[middle] < target) {
left = middle + 1;
} else {
return middle;
}
}
return -1;
}
};
/*官方题解 用时0ms*/
class Solution {
public:
int search(vector<int>& nums, int target) {
int left = 0, right = nums.size() - 1;
while(left <= right){
int mid = (right - left) / 2 + left;
int num = nums[mid];
if (num == target) {
return mid;
} else if (num > target) {
right = mid - 1;
} else {
left = mid + 1;
}
}
return -1;
}
};
左闭右开
class Solution {
public:
int search(vector<int>& nums, int target) {
int left = 0, right = nums.size(); //左闭右开时,right初始化为size,不减一!!!
// 因为left == right的时候,在[left, right)是无效的空间,所以使用 <
while(left < right){ //左闭右开,当left=right时循环就停止;
int mid = (right - left) / 2 + left; //防溢出
int num = nums[mid];
if (num == target) { //先处理最简单的情况
return mid;
} else if (num > target) {
right = mid;
} else {
left = mid+1;
}
}
return -1;
}
};
时间复杂度:O(log n)
空间复杂度:O(1)
27:去除元素
题目链接
方法:暴力解法、双值针法(快慢指针)、双指针优化(左右指针)
/*暴力解法*/
class Solution {
public:
int removeElement(vector<int>& nums, int val) {
int num = nums.size();
for (int i=0; i<num; ++i) {
if (val == nums[i]) {
for (int j=i+1; j<num; j++) {
nums[j-1]=nums[j]; //数组整体左移一位
}
i--;
num--;//下标和数组长度减少1
}
}
return num;
}
};
/*双指针法*/
class Solution {
public:
int removeElement(vector<int>& nums, int val) {
int slow = 0, size = nums.size();
//快慢指针,各遍历一次
for (int fast = 0; fast < size; fast++) {
if (nums[fast] != val) {
nums[slow++] = nums[fast];
}
}
return slow;
}
};
复杂度分析:
时间复杂度:O(n),其中 n为序列的长度。只需遍历该序列至多两次,两个指针各一次。
空间复杂度:O(1),只需常数空间保存若干变量。
/*双指针优化*/
class Solution {
public:
int removeElement(vector<int>& nums, int val) {
int left = 0, right = nums.size();
//头尾指针,共同遍历一次
while (left < right) {
if (nums[left] == val) {
nums[left] = nums[right - 1];
right--;
} else {
left++;
}
}
return left;
}
};
复杂度分析:
时间复杂度:O(n),其中 n为序列的长度。只需遍历该序列至多一次(两个指针在最坏的情况下合起来只遍历了数组一次。双指针优化方法避免了需要保留的元素的重复赋值操作。)。
空间复杂度:O(1),只需常数空间保存若干变量。
相关题目推荐 后面抽时间or二刷做
参考链接:
作者:力扣官方题解、Krahets
链接:https://leetcode.cn/problems/binary-search/solutions/980494/er-fen-cha-zhao-by-leetcode-solution-f0xw/
https://leetcode.cn/problems/binary-search/solutions/1/by-jyd-i7xr/
https://leetcode.cn/problems/remove-element/solutions/730203/yi-chu-yuan-su-by-leetcode-solution-svxi/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。