704. 二分查找、27. 移除元素
704.二分查找
重点:要注意是自己定义区间的是左闭右开,还是左闭右闭。
左闭右开的二分查找
耗时 0:6:11
//时间复杂度:O(log n)
//空间复杂度:O(1)
class Solution {
public:
int search(vector<int>& nums, int target) {
int len = nums.size();
int left = 0, right = len;
int mid;
while(left < right) //取到right无意义,所以没有等于
{
mid = (left + right) / 2;
if(nums[mid]==target)
return mid;
else if(target < nums[mid])//目标值在左半区
right = mid;
else
left = mid+1;//目标值在左半区
}
return -1;
}
};
左闭右闭
//时间复杂度:O(log n)
//空间复杂度:O(1)
class Solution {
public:
int search(vector<int>& nums, int target) {
int len = nums.size();
int left = 0, right = len - 1;
int mid;
while(left <= right)// 取到right有意义,所以有等于
{
mid = (left + right) / 2;
if(nums[mid]==target)
return mid;
else if(target < nums[mid])//目标值在左半区
right = mid-1;
else
left = mid+1;//目标值在左半区
}
return -1;
}
};
27.移除元素
第一眼想法:暴力解
耗时 0:5:21
- 循环列表,遇到目标值就删除(把整个后面的数组前移)
- 注意每一次执行玩后移操作后,i要减1。因为如果后面一个元素也是目标值的话,就会漏掉它。
// 时间复杂度:O(n^2)
// 空间复杂度:O(1)
class Solution {
public:
int removeElement(vector<int>& nums, int val) {
int len = nums.size();
for (int i = 0; i < len;i++)
{
if(nums[i]==val)
{
len--;
for (int j = i; j < len;j++){
nums[j] = nums[j + 1];
}
i--;
}
}
return len;
}
};
看完文档思路:快慢指针;
遇到列表问题要经常考虑双指针解法。
耗时 0:25:34
- 快指针遇到目标值就跳过,目的是指向非目标值,便于覆盖慢指针上的元素。
- 当快指针遇到目标值的回合,慢指针不会移动,目的是指向待处理的元素。
- 当快指针指向非目标值,而慢指针又慢于快指针时,说明该执行覆盖操作。
// 时间复杂度:O(n)
// 空间复杂度:O(1)
class Solution {
public:
int removeElement(vector<int>& nums, int val) {
int slow = 0, fast = 0;
int len = nums.size();
while(slow < len)
{
if(nums[fast] == val)
{
fast++;
len--;
}
else if(slow < fast)
{
nums[slow] = nums[fast];
slow++;
fast++;
}
else
{
fast++;
slow++;
}
}
return len;
}
};
看完答案:发现后面两个判断可以归为一类
// 时间复杂度:O(n)
// 空间复杂度:O(1)
class Solution {
public:
int removeElement(vector<int>& nums, int val) {
int slow = 0, fast = 0;
int len = nums.size();
while(slow<len)
{
if(nums[fast]==val)
{
fast++;
len--;
}
else
{
nums[slow] = nums[fast];
fast++;
slow++;
}
}
return len;
}
};