代码随想录刷题记录
数组
二分查找基本题
题目:找target,关键字:升序,无重复元素,分三种情况讨论结构更清晰
var search = function(nums, target) {
let l = 0, r = nums.length - 1;
while(l<=r){
let m = l + Math.floor((r-l)>>1);
if(nums[m]>target){
r = m - 1;
}else if(nums[m]<target){
l = m + 1;
}else{
return m;
}
}
return -1;
};
二分查找提升题
题目:给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。 分析:有四种情形:
- target比nums[0]小,那么插入的位置是0
- target比nums[len-1],那么插入的位置是len-1,即最后一个位置
- target存在数组中,比如5和[1,2,5,6],那么插入的位置就是index = 2.
- target在两个元素之间,比如4和[1,3,5],那么插入的位置就是index = 2.
let l = 0, r = nums.length - 1;
let ans=nums.length;
while(l<=r){
let m = l + Math.floor((r-l)>>1);
if(nums[m]>target){
r = m - 1;
ans = m;
}else if(nums[m]<target){
l = m + 1;
}else{
return m;
}
}
return ans;
};
这个题的重点是判断这四种情况返回值与middle的关系 除了第三种情况,其余返回的都是循环结束时候的m,第三种情况返回m+1;
先说方法:r指针移动的时候将m值存下来,ans=m,最后返回m,这样就满足了上述返回m和返回m+1的情况
ans的初值是nums.length,如果ans的值一直没有改变,说明一直移动的左指针,target大于最大值。
target小于nums[0]时,循环结束前r和l一定会来到nums[0]的位置,那么ans跟随r的变化也是0。
发现如果target不存在数组里面的话,l和r一定会在一个元素下相遇。
快慢指针
快慢指针一般用来不额外开辟内存,修改数组的值。
题目:删除数组中指定元素
雷区,记住返回return slow
var removeElement = function(nums, val) {
let fast = 0, slow = 0;
while(nums[fast]){
if(nums[fast]!=val){
nums[slow++]=nums[fast];
}
fast++;
}
return slow;
};
没有return slow返回的: 以[2,3,3,2],删除2为例,返回的是[3,3,3,2],因为slow指针走到了index=2的位置,有return slow相当于arr.slice(0,-(len-index)),删除后几项。
滑动窗口
题目:给定一个含有 n 个正整数的数组和一个正整数 target 。
找出该数组中满足其和 ≥ target 的长度最小的 连续子数组 [numsl, numsl+1, ..., numsr-1, numsr] ,并返回其长度。如果不存在符合条件的子数组,返回 0 。
重点:弄清楚左右指针什么时候移动。 右指针负责遍历。
左指针:when:当窗口内容满足要求时,where:左指针移动到哪个位置,与具体情境有关,基本题找满足target最小连续子串,则left++,找水果提升题,则是需要记录第一种水果结束的位置,作为下一次left移动的位置。
var minSubArrayLen = function(target, nums) {
let l = 0, r = 0,sum=0;
// 1.res初始值
let res=nums.length+1;
// 2.循环结束条件
while(r<nums.length){
sum+=nums[r++];
// 3.这里得是while而不是if
while(sum>=target){
res = r-l < res ? r-l : res;
sum-=nums[l];
l++;
}
}
return nums.length < res? 0:res;
};
- 1.res初始值,万一循环结束也没有找到合适的子串,用res来判断
- 2.循环结束条件:右指针到顶
- 3.这里必须是while,写成if就错了,因为while的话,相当于固定了r,然后l移动,缩小窗口,看看有没有达到要求的窗口。