刷题记录———— 二分法
注意:
- 如题,仅记录代码(javascript),同js技术栈的小伙伴可以一起讨论怎么做更好呀~
- 大致是跟着代码随想录的顺序来刷的,感谢Carl老师的总结
-
寻找目标元素的位置(若没有则寻找插入位置):
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; };
-
查找目标元素的起止位置:
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; };
- 你可以设计并实现时间复杂度为
-
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; } } };
-
判断正整数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));