704. 二分查找
704. 二分查找
二分法使用前提:
- 数组为有序数组
- 数组无重复元素
二分法难点:区间的定义,区间的定义就是不变量。 每一次边界的处理都要坚持根据区间的定义来操作,这就是循环不变量规则。
二分法有两种区间定义方式:左右闭合 [left,right], 左闭右开 [left,right)
根据两种区间定义方式,二分法有两种写法,区别在于:
- while循环判断条件
- right的赋值
具体如下:
第一种方式:[left,right]
我的理解:
- while循环判断条件根据区间定义此时应为 left <= right,right的初始值为nums.length-1,left == right 是有意义的。同时,当 left == right时,mid值为最后一次循环需要被判断的值。
- right=mid-1 由于已经判断mid != target,因而应该赋值mid-1,在后面的判断才有意义,left == right时mid的值不会重复判断。
let mid, left = 0, right = nums.length-1
while(left <= right){
mid = left + Math.floor((right-left)/2) //注意取整
if(nums[mid] === target) {
return mid
}else if (nums[mid] > target) {
right = mid-1
}else{
left = mid+1
}
}
return -1
第二种方式:[left,right)
我的理解:
- while循环判断条件根据区间定义此时应为 left < right,right的初始值为nums.length,超过数组下标最大值,当 left == right时,若right=nums.length 则无意义。
- right=mid 由于已经判断mid != target,为了保持 left == right的无意义,所以给right 赋值已经判断不可能是target的mid。
let left = 0, right = nums.length
while(left < right){
const mid = left + Math.floor((right-left)/2)
if(nums[mid] === target) {
return mid
}else if (nums[mid] > target) {
right = mid
}else{
left = mid+1
}
}
return -1
27. 移除元素
暴力解法
暴力解法,太暴力超时了。。。
i-- 是为了在将后一位元素向前移动一位后再次判断这个位置上的元素是否与输入元素相等,解决连续几个元素与输入元素相等的问题。
var removeElement = function(nums, val) {
let k = nums.length
for(let i=0;i<nums.length;i++){
if(nums[i]==val){
for(let j=i+1;j<nums.length;j++){
nums[j-1] = nums[j]
}
i--
k--
}
}
return k
};
双指针法
通过快慢指针用一个for循环完成两个for循环的工作,需要明确快慢指针的定义。
- 快指针:指向要放入新数组的元素
- 慢指针:指向需要更新的新数组的下标位置
在这里 i 是快指针,k 是慢指针,当数组元素等于输入值时,k 不变而 i 持续向前,就形成了快慢指针效果,当数组元素不等于输入值时 k 慢指针才向前移动。
- 时间复杂度:O(n)
- 空间复杂度:O(1)
var removeElement = function(nums, val) {
let k = 0
for(let i=0;i<nums.length;i++){
if(nums[i] != val){
nums[k] = nums[i]
k++
}
}
return k
};