刷题记录———— 二分法

刷题记录———— 二分法

注意:

  • 如题,仅记录代码(javascript),同js技术栈的小伙伴可以一起讨论怎么做更好呀~
  • 大致是跟着代码随想录的顺序来刷的,感谢Carl老师的总结
  1. 寻找目标元素的位置(若没有则寻找插入位置):

    leecode链接:35. 搜索插入位置(难度:简单)

    题目描述:

    给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。

    请必须使用时间复杂度为 O(log n) 的算法。

    //、、示例 1:
    输入: nums = [1,3,5,6], target = 5
    输出: 2
    
    //示例 2:
    输入: nums = [1,3,5,6], target = 2
    输出: 1
    
    //示例 3:
    输入: nums = [1,3,5,6], target = 7
    输出: 4
    

    代码:

    /**
     * 1. 查找插入元素的位置
     * @param {number[]} nums
     * @param {number} target
     * @return {number}
     */
    
    // 二分查找
    var searchInsert = function (nums, target) {
      // 初始化指针
      let left = 0;
      let right = nums.length - 1;
      // 已经超出边界的情况,不进入查找
      if (target <= nums[left]) return left;
      if (target > nums[right]) return right + 1;
      while (left <= right) {
        const mid = left + Math.ceil((right - left) / 2);
        // 找到:
        if (nums[mid] === target) {
          return mid;
        }
        // 没找到:
        // 特殊情况(两指针汇聚,但仍旧没有找到target,需要最终敲定插入位置了)
        if (left === right) {
          return target > nums[mid] ? left + 1 : left;
        }
        target > nums[mid]
          ? (left = mid + 1) // 继续寻找右半边
          : (right = mid - 1); // 继续寻找左半边
      }
      return left;
    };
    
  2. 查找目标元素的起止位置:

    leecode链接: 34. 在排序数组中查找元素的第一个和最后一个位置(难度:中等)

    题目描述:

    给定一个按照升序排列的整数数组 nums,和一个目标值 target。找出给定目标值在数组中的开始位置和结束位置。

    如果数组中不存在目标值 target,返回 [-1, -1]

    进阶:

    • 你可以设计并实现时间复杂度为 O(log n) 的算法解决此问题吗?
    // 示例 1:
    输入:nums = [5,7,7,8,8,10], target = 8
    输出:[3,4]
    
    //示例 2:
    输入:nums = [5,7,7,8,8,10], target = 6
    输出:[-1,-1]
    

    代码:

    • 初始版本(两次循环分别找起、止点):

      /**
       * 2. 查找目标元素的起始位置(原始版本)
       * @param {number[]} nums
       * @param {number} target
       * @return {number[]}
       */
      var searchRange = function (nums, target) {
        // 三种情况:
        // 1. target直接在边界外
        // 2. target在nums中
        // 3. target不在nums中
        let left = 0;
        let right = nums.length - 1;
        // -- 1. target直接在边界外
        if (target < nums[left] || target > nums[right]) {
          return [-1, -1];
        }
        // -- 2. target在nums中
        const res = [-1, -1];
        // 先找左边界
        while (left <= right) {
          const mid = left + Math.ceil((right - left) / 2);
          // 左边界的条件:是目标元素, 且已经是最左边或者其左邻小于其
          if (nums[mid] === target && (mid === 0 || nums[mid - 1] < target)) {
            res[0] = mid;
            break;
          }
          if (target > nums[mid]) {
            left = mid + 1;
          } else {
            right = mid - 1;
          }
        }
        // -- 此时已经可以确定: 3. target不在nums中
        if (res[0] == -1) {
          return [-1, -1];
        }
        // 找右边界
        left = 0; // 恢复现场
        right = nums.length - 1;
        while (left <= right) {
          const mid = left + Math.ceil((right - left) / 2);
          // 右边界的条件:是目标元素, 且已经是最右边或者其右邻大于其
          if (
            nums[mid] === target &&
            (mid === nums.length - 1 || nums[mid + 1] > target)
          ) {
            res[1] = mid;
            break;
          }
          if (target < nums[mid]) {
            right = mid - 1;
          } else {
            left = mid + 1;
          }
        }
        return res;
      }
      
      
    • 略升级版(加指针、减循环次数,起止点同时进行查找)

      /**
       * 2. 查找目标元素的起始位置(加指针、减循环次数)
       * @param {number[]} nums
       * @param {number} target
       * @return {number[]}
       */
      var searchRange1 = function (nums, target) {
        // 两种情况:
        // 1. target直接在边界外
        // 2. target在边界中(但不一定存在)
        const res = [-1, -1];
      
        // 左边界指针
        let l_left = 0;
        let l_right = nums.length - 1;
        // -- 1. target直接在边界外
        if (target < nums[l_left] || target > nums[l_right]) {
          return res;
        }
        // -- 2. target在边界中
        // 右边界指针
        let r_left = l_left;
        let r_right = l_right;
        while (l_left <= l_right || r_left <= r_right) {
          if (res[0] !== -1 && res[1] !== -1) break; // 找到直接跳出、返回结果
          const l_mid = l_left + Math.ceil((l_right - l_left) / 2);
          const r_mid = r_left + Math.ceil((r_right - r_left) / 2);
          // 左边界的部分:
          if (nums[l_mid] === target && (l_mid === 0 || nums[l_mid - 1] < target)) {
            res[0] = l_mid;
          }
          if (target > nums[l_mid]) {
            l_left = l_mid + 1;
          } else {
            l_right = l_mid - 1;
          }
          // 右边界的部分:
          if (
            nums[r_mid] === target &&
            (r_mid === nums.length - 1 || nums[r_mid + 1] > target)
          ) {
            res[1] = r_mid;
          }
          if (target < nums[r_mid]) {
            r_right = r_mid - 1;
          } else {
            r_left = r_mid + 1;
          }
        }
        return res;
      };
      
  3. x的算数平方根:

    leecode链接: 69.x的平方根 (难度:简单)

    题目描述:

    给你一个非负整数 x ,计算并返回 x算术平方根

    由于返回类型是整数,结果只保留 整数部分 ,小数部分将被 舍去 。

    **注意:**不允许使用任何内置指数函数和算符,例如 pow(x, 0.5) 或者 x ** 0.5

    //示例 1:
    输入:x = 4
    输出:2
    
    // 示例 2:
    输入:x = 8
    输出:2
    解释:8 的算术平方根是 2.82842..., 由于返回类型是整数,小数部分将被舍去。
    

    代码:

    /**
     * 3. x的算数平方根(仅保留整数部分)
     * @param {number} x
     * @return {number}
     */
    var mySqrt = function (x) {
      //  二分搜索定位
      if (x <= 1) return x;
      let left = 1;
      let right = x;
      while (left <= right) {
        const mid = Math.floor((left + right) / 2);
        const mult = mid * mid;
        if (mult <= x && (mid + 1) * (mid + 1) > x) {
          return mid;
        }
        if (mult > x) {
          right = mid;
        }
        if (mult < x) {
          left = mid;
        }
      }
    };
    
  4. 判断正整数x是否为完全平方数:

    leecode链接: 69.x的平方根 (难度:简单)

    题目描述:

    给定一个 正整数 num ,编写一个函数,如果 num 是一个完全平方数,则返回 true ,否则返回 false 。

    进阶:不要 使用任何内置的库函数,如 sqrt 。

    //示例 1:
    输入:num = 16
    输出:true
    
    //示例 2:
    输入:num = 14
    输出:false
    

    代码:

    /**
     * 4. 判定完全平方整数
     * @param {number} num
     * @return {boolean}
     */
    var isPerfectSquare = function (num) {
      if (num === 1) return true;
      let left = 1;
      let right = num;
      //   相差1时就说明此时的left与right中间已经没有数,无需再继续往下判定了
      while (left + 1 < right) {
        const mid = Math.floor((left + right) / 2);
        const mult = mid * mid;
        if (mult === num) {
          console.log(mid);
          return true;
        }
        mult > num ? (right = mid) : (left = mid);
      }
      return false;
    };
    console.log(isPerfectSquare(36));
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值