代码随想录算法训练营第一天| 704. 二分查找、27. 移除元素
数组
704.二分查找
mydemo
class Solution {
public:
int search(vector<int>& nums, int target) {
int len = nums.size();
//cout << len;
int left = 0;
int right = len-1;
int mid = (left + right) / 2;
while(left <= right)
{
if(nums[mid] < target)
{
left = mid + 1;
mid = (left + right) / 2;
}
if(nums[mid] == target)
return mid;
if(nums[mid] > target)
{
right = mid - 1;
mid = (left + right) / 2;
}
}
return -1;
}
};
为什么是
left = mid + 1; right = mid - 1
而不是
left = mid; right= mid;
解答
其实在发生大小判断进入更新left或right的分支后,mid就已经被排除在外了,所以不用考虑mid所在位置,+1或者-1进行移动即可。
而且移动有一个好处,就是可以让left何right重叠甚至是反向(right在left前面),这是跳出循环的重要条件
而且不进行移动的话,考虑一种极限情况:
[7,8], target = 8
left = 0, right = 1,mid = 0;
你会发现无论怎么样mid都无法到达target。
要是target过大或过小不在数组里,这个算法怎么输出-1呢?
解
关键:
while(left <= right)
target过大,left会不断朝着right移动,到达临界点(left = right),然后继续变大,跳出循环
target过小则反之
为什么是
while(left <= right)
而不是
while(left < right)
解
考虑一种极限情况,即数组一开始就只有一个元素 {5},
令 target = 5
那么:
mid = 0 ,left = 0, right = 0
left 等于 right,无法进入循环进行二分查找,从而输出-1,这是显然是错误的
27.移除元素
1 暴力解法
my demo:
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)
{
//cout << "i=" << i << endl;
if(nums[i] == val)
{
if(i==len)
len--; //不加的话,当i=len-1时,nums[j] = nums[j+1];有可能会越界
else
{
for(int j = i; j < len-1; j++)
{
nums[j] = nums[j+1];
}
len--;
i--; //不加这一行,在 0,1,2,2,3,val=2这种要删除的元素重复出现的时候会出错
}
}
}
}
return len;
}
};
2 快慢指针法
my demo
class Solution {
public:
int removeElement(vector<int>& nums, int val) {
int len = nums.size();
int slow = 0;
for(int fast = 0; fast < len; fast++)
{
if(nums[fast] != val)
{
nums[slow] = nums[fast];
slow++;
}
}
return slow;
};
};
优化版:
nums[slow] = nums[fast];
slow++;
改为
nums[slow++] = nums[fast];