一、704.二分查找
二分查找是LeetCode上一段非常经典的例题,而二分法也是十分重要的算法之一。由于笔者求职方向是前端工程师,本篇及之后的博客都主要以JavaScript作为编程语言。点击右侧的链接可以跳转至题目:704.二分查找。
当我们看到这一题目的时候,对于没有系统性学过数据结构的同学,上来会先选择暴力解法,暴力解法的代码如下:
/**
* @param {number[]} nums
* @param {number} target
* @return {number}
*/
var search = function(nums, target) {
for(let i = 0;i < nums.length;i++){
if(nums[i] === target){
return i;
}
}
return -1;
};
暴力解法的原理非常简单:一个for循环进行遍历,之后就能得出结果。
除此之外,我们接下来要介绍的就是本期的重点二分法,代码如下所示:
/**
* @param {number[]} nums
* @param {number} target
* @return {number}
*/
var search = function(nums, target) {
let left = 0;
let right = nums.length;
while(left < right){
let mid = left + Math.floor((right - left) / 2);
if(nums[mid] === target){
return mid;
}
else if(nums[mid] > target){
right = mid;
}
else if(nums[mid] < target){
left = mid + 1;
}
}
return -1;
};
在二分法中,我采用的是左闭右开的区间设计。原理其实同样很好理解,先声明left和right两个变量,left代表左侧的起始位置0,而right代表数组的长度。我们的数组就在[0,nums.length)的区间里面。
接下来我们设计一个while循环,while循环的条件(left < right)意味着只有区间里存在数组,才继续进行循环。然后我们声明一个在while循环里的变量mid,mid是left和right的平均值。值得注意的是,由于JS的变量声明不像Java或Python,整数做完除法如果没法除尽,将会变成浮点数。因此需要在得出结果之前增加一个**Math.floor()**函数。
之后,我们就可以进行接下来的判断了,如果nums[mid]的值等于target,那我们就将mid的值return出来。当出现其它情况的时候,我们就可以根据nums[mid]和target之间的大小在左侧或右侧缩小区间,而新的left或right又会被代入循环,直至循环结束找到相等的值或返回-1.
二、35.搜索插入位置
LeetCode的35题搜索插入位置也是一道非常经典的二分查找类题目,该题目的代码如下:
/**
* @param {number[]} nums
* @param {number} target
* @return {number}
*/
var searchInsert = function(nums, target) {
if(target < nums[0]){
return 0;
}
if(target > nums[nums.length - 1]){
return nums.length;
}
let left = 0;
let right = nums.length;
while(left < right){
let mid = left + Math.floor((right - left) / 2);
if(nums[mid] === target){
return mid;
}
else if(target > nums[mid - 1] && target < nums[mid]){
return mid;
}
else if(target > nums[mid] && target < nums[mid + 1]){
return mid + 1;
}
else if(target <= nums[mid - 1]){
right = mid;
}
else if(target >= nums[mid + 1]){
left = mid + 1;
}
}
return 0;
};
总体而言,该题的整体思路与二分查找是相似的。但由于该题多了:如果目标值不存在于数组中,返回它将会被按顺序插入的位置的条件。因此我们需要考虑更多的情况。
首先,在函数的开头设计两个if条件判断目标值是否在区间外,若都不是,则target应在区间内有对应的值或者在区间内的两个值之间。
接下来跟704题相似地,我们继续进行while循环,在该while循环里我们判断的条件就更多了,直接返回值的有三个条件:1.值相等,2. 在nums[mid-1]和nums[mid]之间,3.在nums[mid]和nums[mid+1]之间,在这三种情况都可以立即返回值。而对于剩下两种情况,类似704题继续缩小区间进行循环,然后就能得到我们的答案啦!
三、27.移除元素
移除元素也是一道非常经典的LeetCode题目,在该题中我们采用的是双指针法(快慢指针法),具体代码如下:
/**
* @param {number[]} nums
* @param {number} val
* @return {number}
*/
var removeElement = function(nums, val) {
let slow = 0;
let fast = 0;
for(;fast < nums.length;fast++){
if(nums[fast] !== val){
nums[slow++] = nums[fast];
}
}
return slow;
};
该题的思路非常简单,首先声明两个指针,一慢一快,然后利用快指针进行遍历。如果快指针指向的数等同于val,那么慢指针不变,快指针继续遍历;如果不等同的话,那么快指针将所指向的数传递给慢指针,同时慢指针向后移动一格。如此循环,最后我们得到的慢指针的数值就是我们想要的答案。