leetcode刷题-二分查找&分治
1、在一个重复元素的数组中查找key的最左位置
var binarySearch(nums, key) {
let left = 0, right = nums.length - 1;
while(left < right) {
let mid = Math.floor(left + (right - left) / 2);
if (nums[mid] >= key) {
right = mid;
} else {
left = mid + 1;
}
}
return left;
}
2、x 的平方根
实现 int sqrt(int x) 函数。
计算并返回 x 的平方根,其中 x 是非负整数。
由于返回类型是整数,结果只保留整数的部分,小数部分将被舍去。
var mySqrt = function(x) {
if (x <= 1) return x;
let left = 1, right = x;
while(left <= right) {
const mid = Math.floor(left + (right - left) / 2);
const value = mid ** 2;
if (value === x) {
return mid;
} else if (value > x) {
right = mid - 1;
} else {
left = mid + 1;
}
}
return right;
};
3、寻找比目标字母大的最小字母
给你一个排序后的字符列表 letters ,列表中只包含小写英文字母。另给出一个目标字母 target,请你寻找在这一有序列表里比目标字母大的最小字母。
在比较时,字母是依序循环出现的。举个例子:
如果目标字母 target = 'z' 并且字符列表为 letters = ['a', 'b'],则答案返回 'a'
var nextGreatestLetter = function(letters, target) {
const n = letters.length;
if (target >= letters[n - 1]) {
return letters[0];
}
let left = 0, right = n - 1;
while(left <= right) {
const mid = Math.floor(left + (right - left) / 2);
if (letters[mid] > target) {
right = mid - 1;
} else {
left = mid + 1;
}
}
return letters[left];
};
4、第一个错误的版本
你是产品经理,目前正在带领一个团队开发新的产品。不幸的是,你的产品的最新版本没有通过质量检测。由于每个版本都是基于之前的版本开发的,所以错误的版本之后的所有版本都是错的。
假设你有 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 left = 0, right = n;
while(left <= right) {
const mid = Math.floor(left + (right - left) / 2);
if (isBadVersion(mid)) {
right = mid - 1;
} else {
left = mid + 1;
}
}
return left;
};
};
5、寻找旋转排序数组中的最小值
已知一个长度为 n 的数组,预先按照升序排列,经由 1 到 n 次 旋转 后,得到输入数组。例如,原数组 nums = [0,1,2,4,5,6,7] 在变化后可能得到: 若旋转 4 次,则可以得到 [4,5,6,7,0,1,2] 若旋转 7 次,则可以得到 [0,1,2,4,5,6,7] 注意,数组 [a[0], a[1], a[2], ..., a[n-1]] 旋转一次 的结果为数组 [a[n-1], a[0], a[1], a[2], ..., a[n-2]] 。
给你一个元素值 互不相同 的数组 nums ,它原来是一个升序排列的数组,并按上述情形进行了多次旋转。请你找出并返回数组中的 最小元素 。
var findMin = function(nums) {
let left = 0, right = nums.length - 1;
while (left < right) {
const mid = Math.floor(left + (right - left) / 2);
if (nums[mid] > nums[right]) {
left = mid + 1;
} else {
right = mid;
}
}
return nums[left];
};
6、 在排序数组中查找元素的第一个和最后一个位置
给定一个按照升序排列的整数数组 nums,和一个目标值 target。找出给定目标值在数组中的开始位置和结束位置。
如果数组中不存在目标值 target,返回 [-1, -1]。
var searchRange = function(nums, target) {
const left = findLeft(nums, target);
const right = findLeft(nums, target + 1) - 1;
if (left < nums.length && nums[left] === target) {
return [left, right];
}
return [-1, -1];
};
function findLeft(nums, target) {
const n = nums.length;
if (target > nums[n - 1]) return n;
let left = 0, right = nums.length - 1;
while(left < right) {
const mid = Math.floor(left + (right - left) / 2);
if (nums[mid] >= target) {
right = mid;
} else {
left = mid + 1;
}
}
return right;
}
7、为运算表达式设计优先级
给定一个含有数字和运算符的字符串,为表达式添加括号,改变其运算优先级以求出不同的结果。你需要给出所有可能的组合的结果。有效的运算符号包含 +, - 以及 * 。
var diffWaysToCompute = function(expression) {
const n = expression.length;
const res = [];
const value = Number(expression);
if (!isNaN(value)) return [value];
for (let i = 0; i < n; i++) {
const char = expression[i];
let leftArr = [], rightArr = [];
if (char === '+' || char === '-' || char === '*') {
leftArr = diffWaysToCompute(expression.substring(0, i));
rightArr = diffWaysToCompute(expression.substring(i + 1, n));
}
for (let x of leftArr) {
for (let y of rightArr) {
switch(char) {
case '+':
res.push(x + y);
break;
case '-':
res.push(x - y);
break;
case '*':
res.push(x * y);
break;
}
}
}
}
return res;
};