提示:努力生活,开心、快乐的一天
704.二分查找
💡解题思路
- 二分查找的前提条件:
有序数组+无重复元素
- 题目中数组的左右边界,主要分为2种边界:
[left,right]和[left,right)
- 坚持
循环不变量
原则,此题中的不变量就是区间
- 边界处理
[left,right]
:
-
nums[mid]>target时,需要更新右边界的值,right = middle-1(此处!=middle的原因是:遵循区间不变原则,右区间为闭区间,则nums[mid]可能等于target,但进入该判断条件的前提是nums[mid]>target,两者相悖,所以!=middle);
-
nums[mid]<target时,此时需要更新左边界的值,left = middle+1(原因与更新右边界一样,两者一个+1,一个-1,主要是更新的左右边界原因)
[left,right)
-
nums[mid]>target时,此时需要更新右边界的值,right = middle(此处=middle的原因是:遵循区间不变原则,右区间为开区间,则nums[mid]不可能等于target,但进入该判断条件的前提是nums[mid]>target,两者一致,所以=middle);
-
nums[mid]<target时,此时需要更新左边界的值,left = middle+1(此处!=middle的原因是:遵循区间不变原则,左区间为闭区间,则nums[mid]可能等于target,但进入该判断条件的前提是nums[mid]<target,两者相悖,所以!=middle)
🤔遇到的问题
-
mid的取值问题,(left+right)/2 会产生溢出情况
解决方案:使用>>
运算符 -
边界处理上,一看就会,一些就废,眼高手低啦
💻代码实现
[left,right]
var search = function (nums, target) {
let left = 0;
let right = nums.length - 1;
while (left <= right) {
let mid = (right + left) >> 1
if (nums[mid] > target) {
right = mid - 1
} else if (nums[mid] < target) {
left = mid + 1
} else {
return mid
}
}
return -1;
};
[left,right)
var search = function (nums, target) {
let left = 0;
let right = nums.length;
while (left < right) {
let mid = (right + left) >> 1
if (nums[mid] > target) {
right = mid
} else if (nums[mid] < target) {
left = mid + 1
} else {
return mid
}
}
return -1;
};
🎯题目总结
- 数组满足
二分查找的条件
确定查找的区间,是[left,right]还是[left,right)
- mid取值不可溢出,使用
>>
运算符 - 对于
[left,right]
right
值就是数组最后一位的下标
while
循环的条件遵循区间不变规则,left<=right
判断条件分3种情况:
nums[mid] > target
:target值在左区间,更新右区间值为[left,mid-1]
nums[mid] < target
:target值在右区间,更新右区间值为[mid+1,right]
nums[mid] = target
:return mid
不满足循环,return -1 - 对于
[left,right)
right
值就是数组的长度
while
循环的条件遵循区间不变规则,left<right
判断条件分3种情况:
nums[mid] > target
:target值在左区间,更新右区间值为[left,mid)
nums[mid] < target
:target值在右区间,更新右区间值为[mid+1,right)
nums[mid] = target
:return mid
不满足循环,return -1
27、移除元素
💡解题思路
- 需
原地
移除元素,所以不能new一个新的数组 - 暴力解法:
双层for循环
,第一层,遍历数组;某元素与val值相同时,进行第二层循环,将其后的元素往前移动,时间复杂度: O(N^2),空间复杂度:O ( 1 ) - 双指针解法:定义快慢两个指针,
fast
指针代表新数组的元素,slow
指针代表新数组的下标,当fast
指针遇到val时,直接跳过,等待slow
指针将其覆盖,从而达到删除元素的效果;如果fast
指针遇到值不等于val
的元素,将其值赋值给slow
指针,然后让slow
指针前进一步。
🤔遇到的问题
- 循环时不自觉就写成给nums.length-1
- 暴力解法时,第一层循环向前移动一位时,错写成江第二层循环往前移动一位
💻代码实现
暴力解法
var removeElement = function (nums, val) {
//暴力解法
let len = nums.length
for (let i = 0; i < len; i++) {
if (nums[i] === val) {
for (let j = i + 1; j < len; j++) {
nums[j - 1] = nums[j]
}
i--;
len--;
}
}
return len;
};
双指针解法
var removeElement = function (nums, val) {
//双指针
let slow = 0
for (let i = 0; i < nums.length; i++){
if (nums[i] !== val) {
nums[slow] = nums[i]
slow++
}
}
return slow;
};
🎯题目总结
双指针经常用于处理数组和链表相关问题,主要利用了数组连序性
的特点。优点是降低算法的时间复杂度,因为使用两个指针可以避免多层循环。双指针技巧主要分为两类:左右指针
和快慢指针
。本题使用到了快慢指针。
🎈今日心得
一边上班一边刷题,先看题,发散思维,梳理自己的思路,再看视频,再看文字版解析,再编码,最后写博客(第一次写,很浪费时间)。时间比较散,因为偶尔对需求,偶尔改bug,偶尔开会。但还是完成了。欣崽棒棒哒