代码随想录算法训练营第一天|LetCode704.二分查找、Letcode27移除元素
LetCode704.二分查找
先展示一下代码:
**声明:**代码是我原创的,我是跟着y总的学的,起始跟y总学的时候没有感觉到他的算法教学多么好,直到近期,做了几道题,发现y的方法还是比较好用的。
class Solution {
public:
int search(vector<int>& nums, int target) {
int l = 0,r = nums.size() - 1,mid;
while(l < r)
{
mid = (l + r) / 2;
if(nums[mid] >= target) r = mid;
else l = mid + 1;
}
if(nums[r] != target) return -1;
else return r;
}
};
解释一下代码:二分要保证要操作的数组是有序的,这样才能进行二分,首先确定两个端点l,r,然后确定mid(这里我使用的是(l+r)/2的方式,还有别的吗?还真有),然后只要l还小于r的时候就一直在循环,直l>=r的时候才跳出循环,l>r的时候肯定要跳出循环,因为都找完了,l == r的时候,这时候是l、r、mid三个指针都指向同一个元素,也意味着查找完毕,所以也会跳出循环。最后如果nums[r]!=target,就返回-1,否则就返回查找到的下标。
一些朋友肯定首先有个疑问是:为什么返回的是r?不是mid?
因为,while里面循环比较的时候是nums[mid] >=target,所以是包含了nums[mid] = target这种情况的,所以r和mid其实是一个效果。
二分查找的思路
y总的课里,二分查找有两个思路,y的话说就是,二分的本质就是找边界点,这里就是确定mid:
- 第一种mid可以被确定为(l + r + 1) / 2。此时mid更新的边界是[l,mid - 1]和[mid,r] ,若target在前者中,则r = mid - 1;否则l = mid,此时最后返回是l。
- 第二种mid可以被确定为(l + r) / 2。此时mid更新的边界就是[l,mid]和[mid+1,r],若target在前者中,则r = mid,否则l = mid + 1,此时最后返回是r。
LetCode 27.移除元素
首先先上一下暴力:
`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(int j = i + 1;j < size;j++)
{
nums[j - 1] = nums[j];
}
i--;
size--;
}
}
return size;
}
};`
有时候就感觉自己学的太死板,也学了几个模板了,反而以前最擅长的暴力开始陌生了,我就说一下我的两个关注点吧。
第一个是nums[j - 1] = nums[j];这句,这句我开始用的是j = i,nums[j] = nums[j + 1];,所以当i和j走到最后的时候,数组末尾是没有元素的,这样就超出边界了,还有nums[j - 1] = nums[j];也不行,因为当j为0的时候也出界了。
第二个是i–;size–; 这两句,如果没有这两句也会越界。
下面是用双指针做的:
`class Solution {
public:
int removeElement(vector<int>& nums, int val) {
int slow = 0;
for(int fast = 0;fast < nums.size();fast++)
{
if(nums[fast] != val)
nums[slow++] = nums[fast];
}
return slow;
}
};`
这里的话我觉得代码随想录里的更明了一些,虽然和y的代码一样,但是使用slow和fast就会很容易分析代码过程。
讲解文档:https://programmercarl.com/0027.%E7%A7%BB%E9%99%A4%E5%85%83%E7%B4%A0.html#%E6%80%9D%E8%B7%AF