代码随想录Day1-Leetcode704-二分查找、Leetcode-27移除元素
704. 二分查找
题目链接:https://leetcode.cn/problems/binary-search/
很经典,很基础的一个算法
但说实话, 我一直对着这个算法的细节掌握不够, 按道理都写过很多次了, 但这次还是写错了
第一次写的代码如下
function search(nums: number[], target: number): number {
let l:number = 0, r:number = nums.length-1;
while(l<r){ //选择了< 而非<=
let mid:number = (l+r)>>1
if(target>nums[mid]){
l = mid+1
}else if(target<nums[mid]){
r = mid//选择了r=mid 而非r= mid-1
}else{
return mid
}
}
return -1;
};
这个算法有一个明显的缺陷是:
循环终止条件是lr, 那么, 如果此时恰好nums[l]target呢?
例如, 输入用例[1,2] 2 ,循环在lr1处终止, 返回-1;
那么一个不那么优雅的解决方法是, 返回前检查一下nums[l]==target是否成立
return nums[l]==target?l:-1
那么如果把第一处注释改为<=呢,结论是会超时,因为注释第二处的r=mid;
在l==r时, 如果target不存在与nums中, 而又恰好target < nums[mid] , 会因为r=mid导致无限循环;
所以结果是若选择<= 则应当有left = mid+1; 和right = mid-1;
最终的结果应当如下
function search(nums: number[], target: number): number {
let l:number = 0, r:number = nums.length-1;
while(l<=r){
let mid:number = (l+r)>>1
if(target>nums[mid]){
l = mid+1
}else if(target<nums[mid]){
r = mid-1
}else{
return mid
}
}
return -1;
};
但看过代码随想录的文章后,
我才明白原来这两种算法对应的分别是"左闭右开"和"左闭右闭"的查找
左闭右开时,为了保持每次循环都是左闭右开,left取mid+1, right取mid;
同时left==right没有意义, 所以边界条件为left < right;
左闭右闭同理
而我犯的错误就是作者总结的错误,看来我的算法的理论水平还远远有待提高!
这里记录下我遗漏的几个理论知识点:
1.这道题目的前提是数组为有序数组,同时题目还强调数组中无重复元素
2.while寻找中每一次边界的处理都要坚持根据区间的定义来操作,这就是循环不变量规则
3.注意溢出的问题,应当用mid = left+(right-left)>>1 这里我用了ts没有注意;
而这里有一些拓展题目, 出于时间我暂且不刷
27. 移除元素
题目链接:https://leetcode.cn/problems/remove-element/
和线性表的删除很像(应该说就是), 不过我的效率好像炸了;
//思路, 遍历, 记录一个回跳长度,每遇到val就+=1, 非val回跳len
function removeElement(nums: number[], val: number): number {
let jLen:number = 0;
let len:number = nums.length;
for(let i = 0; i< nums.length; i++){
if(nums[i] == val){
jLen++;
len--;
}else{
nums[i-jLen] = nums[i];
}
}
return len;
};
看了文章后, 发现可以用快慢双指针解释这个方法;

浙公网安备 33010602011771号