第一题,折半查找
一直都是一个比较迷糊的算法,迷糊的地方今天看完讲解文章之后可谓是茅塞顿开。之前一直做不好的地方就是区域边界。现在了解了,折半查找分为,左闭右开和左闭右闭,我一直习惯的是左闭右闭,相对应的关键点就是:不管是递归还是循环的判定条件都是(l<=r),因为,当r==l时,此时这种情况仍然是有意义的。
问题:
1.r<r
2.突然懵了,忘记去判断nums[mid]和target的大小,从而去更新搜索空间,还想着怎么去返回两次调用递归函数的结果
3.target和nums[mid]的大小决定搜索数组的范围,不要左右搞反
源码:
class Solution {
public:
int search(vector<int>& nums, int target) {
int size = nums.size();
int l=0,r=size-1;
return mid_search(l,r,nums,target);
}
int mid_search(int l,int r,vector<int>& nums,int target){
if(l<=r){
int mid = (l+r)/2;
if(nums[mid]==target)
return mid;
else if(target<nums[mid])
return mid_search(l,mid-1,nums,target);
else if(nums[mid]<target)
return mid_search(mid+1,r,nums,target);
}
return -1;
}
};
第二题移除数组元素:
方法一:暴力,每次找到需要覆盖的元素,只需将它之后剩余的元素一次往前移动即可,这个判定结束的条件有两种思路,一种是一直记录目前还没有检查过的数组元素个数,另一种是实时更新数组的size,有size就好说
方法二:双指针(越妙的代码越隐含了很多常见代码会想告知你的信息,不会像正常代码那样,结构简明,告诉你这一步要干什么,接下来它要干什么了,妙码需要去推敲)
下面这个代码,叫做快慢指针,光是理解这个快慢,我就花了不少功夫,循环中只说了当快指针检查到了不是val时怎么处理,实际上当检查到val时,这一隐藏的情况才是指针区别出快慢的关键步骤。
class Solution {
public:
int removeElement(vector<int>& nums, int val) {
int fast,low,size = nums.size(),count = 0;
for(fast=0,low=0;fast<size;fast++){
if(nums[fast]!=val){
nums[low]=nums[fast];
low++;
}
}
return low;
}
};