题目分类 :二分查找
时间:2020-09-08
题目一 :数组交集
给定两个数组,编写一个函数来计算它们的交集。
示例 1:
输入:nums1 = [1,2,2,1], nums2 = [2,2]
输出:[2,2]
示例 2:
输入:nums1 = [4,9,5], nums2 = [9,4,9,8,4]
输出:[4,9]
思路
解法一 : 哈希表法
遍历第一个数组时利用哈希表记录所有数字的出现频率,遍历第二个数组时可以快速查询哪些元素在第一个数组中曾经出现,遍历完毕后即可得到两数组的交集。
代码
let res = [];
let map = {};
for (let i = 0; i < nums1.length; i++) {
if (map[nums1[i]] != undefined) {
map[nums1[i]]++;
} else {
map[nums1[i]] = 1;
}
}
for (let j = 0; j < nums2.length; j++) {
if (map[nums2[j]] != undefined && map[nums2[j]] != 0) {
res.push(nums2[j]);
map[nums2[j]]--;
}
}
return res
解法二 : 二分查找
使用sort函数将其中一个数组排序,再使用二分查找筛选出两数组交集。
代码
nums2.sort((a, b) => a - b);
let resArr = [];
var searchNumber = function (target) {
let left = 0;
let right = nums2.length-1;
if (nums2[left] == target) {
nums2.splice(left, 1)
return true;
}
if (nums2[right] == target) {
nums2.splice(right, 1)
return true;
}
while (left < right-1) {
let mid = Math.floor((left + right) * 0.5);
if (nums2[mid] == target) {
nums2.splice(mid, 1);
return true;
}
if (nums2[mid] < target) {
left = mid;
}
if (nums2[mid] > target) {
right = mid;
}
}
return false;
}
for (let i = 0; i < nums1.length; i++) {
if (searchNumber(nums1[i])) {
resArr.push(nums1[i])
}
}
return resArr;
题目二 :X的平凡根
计算并返回 x 的平方根,其中 x 是非负整数。
由于返回类型是整数,结果只保留整数的部分,小数部分将被舍去。
示例 1:
输入: 4
输出: 2
示例 2:
输入: 8
输出: 2
说明: 8 的平方根是 2.82842…,
由于返回类型是整数,小数部分将被舍去。
思路
题目只要求返回整数部分,因此可在一个有序递增数组【1,2,3…x】中寻找一个数n,使得n的平方小于x,(n+1)的平方大于x,那么n即为x的平方根。在有序数组中查找数据,还是使用典型的二分查找方法。
代码
let left = 0;
let right = x;
if (x == 0 || x == 1) return x;
while (left < right - 1) {
let mid = Math.floor((left + right) * 0.5)
if (mid * mid == x) {
return mid
}
if (mid * mid < x) {
if ((mid + 1) * (mid + 1) > x) {
return mid
} else {
left = mid;
}
}
if (mid * mid > x) {
if ((mid - 1) * (mid - 1) < x) {
return (mid-1)
}else{
right = mid;
}
}
}
题目三 :旋转数组中的最小数字
把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。输入一个递增排序的数组的一个旋转,输出旋转数组的最小元素。例如,数组 [3,4,5,1,2] 为 [1,2,3,4,5] 的一个旋转,该数组的最小值为1。
示例 1:
输入:[3,4,5,1,2]
输出:1
示例 2:
输入:[2,2,2,0,1]
输出:0
思路
题目的难点在于使用二分查找后,范围的选择和逼近方式的判断。主要的判断步骤写在代码的注释中,条理相对更清晰一些
代码
var minArray = function (numbers) {
let left = 0;
let right = numbers.length - 1;
while (left < right - 1) {
let mid = Math.floor((left + right) * 0.5);
if (numbers[mid] > numbers[right]) { //当right指针的值小于mid指针指向的数值时,最小值在mid右侧,如数组[7,8,9,10,11,12,1,2,3],此时mid指向11,right指向3
left = mid;
continue;
}
if (numbers[mid] < numbers[right]) { //当right指针的值大于mid指针指向的数值时,最小值在mid左侧,如数组[10,6,7,8,9],此时mid指向7,right指向9
right = mid
continue;
}
if (numbers[mid] == numbers[right]) {
//当mid指向的值和right指向的值相等时,最小值可能在左侧(如[11,5,6,7,7,7,7],此时mid和right均指向7)、右侧(如数组[7,7,7,7,5,6,7],此时,mid与right均指向7)或本身(如数组[7,7,7])
right--;
//取另一个right
if (right == mid) {
right = mid;
}
}
}
if (numbers[left] < numbers[right]){
return numbers[left]
}else{
return numbers[right]
}
};