leetcode——二份查找

112 阅读1分钟

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。