【704】二分查找
| Category | Difficulty | Likes | Dislikes |
|---|---|---|---|
| algorithms | Easy (56.01%) | 280 | - |
给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1。
个人解法
var search = function (nums, target) {
if (!nums.includes(target)) {
return -1;
}
if (nums[0] === target) {
return 0;
}
if (nums[1] === target) {
return 1;
}
let mid = parseInt(nums.length / 2)
if (nums[mid] < target) {
for (let i = mid + 1; i < nums.length; i++) {
if (target === nums[i]) return i;
}
} else {
for (let j = 0; j < mid; j++) {
if (target === nums[j]) return j;
}
}
}
Accepted
- 46/46 cases passed (84 ms)
- Your runtime beats 58.95 % of javascript submissions
- Your memory usage beats 39.58 % of javascript submissions (41.3 MB)
分析
之前的思路中,mid固定不变,没有参与循环,实际上只实现了一次二分。于是定义数组下标左右端点l、r,采用求l、r平均值的方式确定mid,mid可以随l、r的变化而改变。
优化
let l = 0, r = nums.length;
while (l <= r) {
let mid = parseInt((l + r) / 2);
if (nums[mid] === target) {
return mid;
} else {
if (r - l === 1) {
return -1; // 只剩下一个数但仍不等于target的情况
}
else if (nums[mid] < target) {
l = mid + 1; // 新的循环范围舍弃mid,因为nums[mid]已经确定不等于target(否则就 return mid了)
}
else if (nums[mid] > target) {
r = mid;
}
}
}
}
Accepted
- 46/46 cases passed (76 ms)
- Your runtime beats 79.62 % of javascript submissions
- Your memory usage beats 5.65 % of javascript submissions (41.6 MB)
【278】第一个错误的版本
| Category | Difficulty | Likes | Dislikes |
|---|---|---|---|
| algorithms | Easy (45.31%) | 362 | - |
你是产品经理,目前正在带领一个团队开发新的产品。不幸的是,你的产品的最新版本没有通过质量检测。由于每个版本都是基于之前的版本开发的,所以错误的版本之后的所有版本都是错的。
假设你有 n 个版本 [1, 2, ..., n],你想找出导致之后所有版本出错的第一个错误的版本。
你可以通过调用 bool isBadVersion(version) 接口来判断版本号 version 是否在单元测试中出错。实现一个函数来查找第一个错误的版本。你应该尽量减少对调用 API 的次数。
个人解法(订误)
var solution = function (isBadVersion) {
/**
* @param {integer} n Total versions
* @return {integer} The first bad version
*/
return function (n) {
// let arr = [];
// for (let i = 0; i <= n; i++) {
// arr.push(i);
// }
// let l = 0, r = arr.length; 删去,不需要构建数组也可以使用二分法。
let l = 1, r = n;
while (l < r) {
let mid = parseInt((l + r) / 2);
//删去。通过将答案区间逼近为1的方法找到目标值。
// if (isBadVersion(arr[mid]) === false && isBadVersion(arr[mid + 1]) === true) return mid + 1;
if (isBadVersion(mid)) { //if条件句本身就是布尔值,唉!
r = mid;
} else
// else if (isBadVersion(arr[mid]) === false) {
l = mid + 1;
// } else {
// r = mid;
// }
}
return l;
};
};
Accepted
- 22/22 cases passed (56 ms)
- Your runtime beats 99.43 % of javascript submissions
- Your memory usage beats 18.61 % of javascript submissions (37.8 MB)
分析
关键点在于,当l=r时,存在目标值的区间长度为1,即找到目标值。并且while循环条件设为l<r,l=r时可以跳出循环,返回结果。
如果将题【704】二分查找 换成同样的写法:
【704】优化
var search = function (nums, target) {
let l = 0, r = nums.length;
while (l < r) {
let mid = parseInt((l + r) / 2);
if (nums[mid] < target) {
l = mid + 1;
}
else {
r = mid;
}
}
if (nums[l] !== target) return -1;
else return l;
}
Accepted
- 46/46 cases passed (72 ms)
- Your runtime beats 88.84 % of javascript submissions
- Your memory usage beats 11 % of javascript submissions (41.5 MB)
同理可优化题【35】:
【35】搜索插入位置
| Category | Difficulty | Likes | Dislikes |
|---|---|---|---|
| algorithms | Easy (46.96%) | 977 | - |
给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。
请必须使用时间复杂度为 O(log n) 的算法。
个人解法
var searchInsert = function(nums, target) {
const n = nums.length;
let left = 0, right = n - 1, ans = n;
while (left <= right) {
let mid = Math.floor((left + right) / 2);
if (target <= nums[mid]) {
ans = mid;
right = mid;
} else {
left = mid + 1;
}
}
return ans;
};
Accepted
- 62/62 cases passed (96 ms)
- Your runtime beats 14.67% of javascript submissions
- Your memory usage beats 26.19 % of javascript submissions (39.6 MB)
优化
var searchInsert = function (nums, target) {
let l = 0, r = nums.length;
while (l < r) {
let mid = parseInt((l + r) / 2);
if (nums[mid] < target) {
l = mid + 1;
} else {
r = mid;
}
}
if (nums[l] < target) return l + 1;
else return l;
};
Accepted
- 62/62 cases passed (76 ms)
- Your runtime beats 75.02 % of javascript submissions
- Your memory usage beats 27.19 % of javascript submissions (38.9 MB)