leetcode——二份查找
题704
给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target写一个函数
搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1。
最基础的二分查找题,主要注意的是区间问题:
let left = 0
let right = length - 1
while(left <= right){
mid = left + Math.floor((right - left) / 2)
if(num[mid] === target){
return mid
}else if(num[mid] < target){
left = mid + 1
}else if(num[mid] > target){
right = mid - 1
}
}
错误原因:循环条件left<=right写成<
题35
给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。
如果目标值不存在于数组中,返回它将会被按顺序插入的位置。
请必须使用时间复杂度为 O(log n) 的算法
多了个一种可能就是target不再num数组中。
在二分查找代码的基础上,while循环外直接返回left,因为这个时候left>right。
错误原因:将找不到的情况直接写在while循环中了!!
题34
给定一个按照升序排列的整数数组 nums,和一个目标值 target。
找出给定目标值在数组中的开始位置和结束位置。
如果数组中不存在目标值 target,返回 [-1, -1]。
var searchInsert = function (nums, target) {
let l = 0, r = nums.length - 1, ans = nums.length;
while (l <= r) {
const mid = l + Math.floor((r - l) >> 1);
if (target < nums[mid]) {
r = mid - 1;
} else {
l = mid + 1
ans = l;
}
}
return ans;
};
做这道题目就一定要二分查找这个写法方便下面的理解。
思路:题目有三种情况,前两种都是找不到的情况,最后一种情况比较重要。
最后一种情况:分两次查找找左右区间。
口诀:寻找左边界就<=里面保存位置,寻找右边界就>=里面保存位置。
if(target <= nums[middle]){
// 寻找左边界,nums[middle] == target的时候更新right
right = middle - 1;
leftBorder = right;
} else {
left = middle + 1;
}
if (target < nums[middle]) {
right = middle - 1;
} else { // 寻找右边界,nums[middle] == target的时候更新left
left = middle + 1;
rightBorder = left;
}
/**
* @param {number[]} nums
* @param {number} target
* @return {number[]}
*/
var searchRange = function(nums, target) {
if(nums.length === 0){return [-1,-1]}
const x = nums.indexOf(target)
if(x === -1) {return [-1,-1]}
const leftBian = leftSearch(nums, target)
const rightBian = rightSearch(nums, target)
if (rightBian - leftBian > 1) return [leftBian + 1, rightBian - 1];
else {return [leftBian, rightBian]}
};
function leftSearch(nums, target) {
let left = 0;
let right = nums.length - 1;
let leftRecord = -1;
while(left <= right){
let middle = left + ((right - left) >> 1);
if(target <= nums[middle]){
right = middle - 1;
leftRecord = right;
}else{
left = middle + 1;
}
}
return leftRecord
}
function rightSearch(nums, target) {
let left = 0;
let right = nums.length - 1;
let rightRecord = -1;
while(left <= right){
let middle = left + ((right - left) >> 1);
if(target < nums[middle]){
right = middle - 1;
}else{
left = middle + 1;
rightRecord = left;
}
}
return rightRecord
}
题69
给你一个非负整数 x ,计算并返回 x 的 算术平方根 。
由于返回类型是整数,结果只保留 整数部分 ,小数部分将被 舍去 。
注意:不允许使用任何内置指数函数和算符,例如 pow(x, 0.5) 或者 x ** 0.5
思路1:x的平方根首先是在1~x之间,我们先计算出mid,拿mid与(x/mid)对比。如果mid^2大于x就说明x的平方根是小于mid(如果(mid+1)^2>x说明mid就是要求的值),否则就是大于mid
思路2:就是找左边界
let left=0
let right=x
while(left<=right){
let mid=left+((right-left)>>1)
if(mid*mid<=x){ // 在mid右边
left=mid+1
}else{//在左边
right=mid-1;
}
}
return right
};
题367
给定一个正整数num,编写一个函数,如果num是一个完全平方数,则返回true,否则返回false。
进阶:不要使用任何内置的库函数,如sqrt 。
这道题其实在上面基础上算出左边界,left^2与x比较就行了。left=0,right=x。