704.二分查找
第一想法
暴力解法,直接遍历整个数组
思路
利用二分法,一步一步缩小搜索区间,注意边界的选取与终止条件的设置
1.[left,right]
-
循环条件设置为while(left < = right)
因为区间是左闭右闭的,所以left = right时有意义,即最终终止条件为left 在 right的右边
-
if(nums[mid] > target) ,right = mid - 1
if(nums[mid < target]), left = mid + 1
JS实现代码如下:
/**
* @param {number[]} nums
* @param {number} target
* @return {number}
*/
var search = function(nums, target) {
let left = 0, right = nums.length - 1, mid = 0;
while(left <= right){
mid = left + parseInt((right - left)/2 );
if(nums[mid] > target){
right = mid - 1;
}else if(nums[mid] < target){
left = mid + 1;
}else{
return mid;
}
}
return -1;
};
2.[left,right)
-
初始条件right = nums.length,这里不需要减1
-
循环条件设置为while(left < right)
因为区间是左闭右开的,所以left = right 已经到终止条件了
-
if(nums[mid] > target) ,right = mid
if(nums[mid < target]), left = mid + 1
因为左边是闭区间,所以left 还是要+1
JS代码如下:
/**
* @param {number[]} nums
* @param {number} target
* @return {number}
*/
var search = function(nums, target) {
let left = 0, right = nums.length, mid = 0;
while(left < right){
mid = left + parseInt((right - left)/2 );
if(nums[mid] > target){
right = mid;
}else if(nums[mid] < target){
left = mid + 1;
}else{
return mid;
}
}
return -1;
};
总结
使用二分法后,算法的时间复杂度从O(N)降低到了O(log2N)
两种方法掌握一种就可以,因为这类题目还有许多变式,所以以后打算统一使用第一种方法
二分法最重要的地方在于边界的选取以及想明白终止条件是什么,容易出现细节上的失误
因为这道题前不久刚学,所以今天做的比较顺畅
27.移除元素
第一想法
数组的插入和删除比较复杂,需要按顺序逐个移动元素。用暴力解法的话,可以遍历一遍数组,对于满足条件的元素,把该元素后面的元素依次往前移一个位置,这样需要使用2个for循环
暴力解法:
/**
* @param {number[]} nums
* @param {number} val
* @return {number}
*/
var removeElement = function(nums, val) {
let i = 0, j= nums.length,k = 0,count = 0;
for(i=0; i<j; i++){
if(nums[i] == val){
for(k=i; k<j-1; k++){
nums[k] = nums[k+1]
}
nums[k] = 0;
count++;
i = i-1; // 因为数组位置移动了,所以这里必须i - 1
}
}
j = j - count;
return j;
};
这题的暴力解法超出时间限制了
思路
双指针法:
利用一个快指针,一个慢指针
当数组的值不等于val时,快慢指针同时+1
如果值等于val,则快指针+1,慢指针不动,即跳过了这个数
最后把慢指针的值返回
相当于用后面的元素把等于val的元素覆盖掉了
JS 代码如下:
/**
* @param {number[]} nums
* @param {number} val
* @return {number}
*/
var removeElement = function(nums, val) {
let slow = 0,fast = 0;
for(fast=0; fast < nums.length; fast++){
if(nums[fast] !== val){
nums[slow++] = nums[fast];
}
}
return slow;
};
总结
双指针法这个思路很重要,需要记住
对于数组这种不方便插入和删除的结构来说,用双指针法对其进行处理会方便许多
今日总结
因为这两道题半个月前学过,所以今天写的比较顺利,做题+写博客一共64分钟
其实二分法也可以视为双指针法,只是指针是相向而行的
双指针的思想还是挺重要的