今日进度:代码随想录 二分法
- 704. 二分查找
- 35.搜索插入位置
- 34.在排序数组中查找元素的第一个和最后一个位置
- 69.x 的平方根
- 367.有效的完全平方数
- 二分法计算要从一开始就确定要用左闭右闭区间还是左闭右开区间
- 左闭右闭区间:
取中点后,移动边界时,
right要移动到mid-1,left要移动到mid+1(因为mid是错误值才会移动区间,移动完的区间依然是两端都可以取值的) - 左闭右开区间:
取中点后,移动边界时,
right要移动到mid,left要移动到mid+1(因为mid是错误值才会移动区间,移动完的区间右边界不取,要取左边界)
-
二分法的mid要用
mid = left + Math.floor((right - left) / 2)的方式来定义。(防止溢出:如果使用(left + right) / 2的方式来计算mid,在left和right都是很大的整数时,它们的和可能会导致整数溢出。使用Math.floor((right - left) / 2) + left确保了中间位置的计算不会溢出,因为它通过减法来防止了大整数相加可能导致的溢出问题。)整数溢出:在JavaScript中,所有数字都被表示为64位浮点数。JavaScript使用IEEE 754双精度浮点数标准来表示数字,这包括整数。因此,JavaScript 中整数溢出的情况与传统的整数溢出概念不同。 在JavaScript中,整数溢出通常表现为超出能够准确表示的最大整数范围而失去精度,而不是引发异常或错误。 最大的安全整数是
Number.MAX_SAFE_INTEGER,其值为9007199254740991。当在JavaScript中进行加法运算并且结果超过这个最大安全整数时,就会发生失去精度的情况。 2^53−1=9007199254740991 -
- 34.在排序数组中查找元素的第一个和最后一个位置
这道题我自己是用了很笨的二分法去查找左右边界
var searchStartOrEnd = function (nums, target, dir) {
let left = 0, right = nums.length - 1, mid = Math.floor(left + (right - left) / 2)
while (left <= right) {
if (nums[mid] < target) {
left = mid + 1
} else if (nums[mid] > target) {
right = mid - 1
} else {
if (dir === 'start') {
if (mid > 0 && nums[mid - 1] < nums[mid] || mid === 0) {
return mid
} else {
right = mid - 1
}
} else {
if (mid < nums.length - 1 && nums[mid + 1] > nums[mid] || mid === nums.length - 1) {
return mid
} else {
left = mid + 1
}
}
}
mid = Math.floor(left + (right - left) / 2)
}
return -1
}
return [searchStartOrEnd(nums, target, 'start'), searchStartOrEnd(nums, target, 'end')]
};
但看了下代码随想录的解答,觉得自己查左右边界的思路有问题,比如查左边界,其实查target那一段左边的那一位就可以,而我非要去找target那一段的第一位,导致代码十分冗余。
const getLeftBorder = (nums, target) => {
let left = 0, right = nums.length - 1;
let leftBorder = -2;// 记录一下leftBorder没有被赋值的情况
while(left <= right){
let middle = left + ((right - left) >> 1);
if(nums[middle] >= target){ // 寻找左边界,nums[middle] == target的时候更新right
right = middle - 1;
leftBorder = right;
} else {
left = middle + 1;
}
//这里的逻辑:因为是找左边界,所以只要middle的值比target大(或等于target),那说明左边界一定在当前的middle的左面,更新一次左边界的值
}
return leftBorder;
}
const getRightBorder = (nums, target) => {
let left = 0, right = nums.length - 1;
let rightBorder = -2; // 记录一下rightBorder没有被赋值的情况
while (left <= right) {
let middle = left + ((right - left) >> 1);
if (nums[middle] > target) {
right = middle - 1;
} else { // 寻找右边界,nums[middle] == target的时候更新left
left = middle + 1;
rightBorder = left;
}
}
return rightBorder;
}
let leftBorder = getLeftBorder(nums, target);
let rightBorder = getRightBorder(nums, target);
// 情况一
if(leftBorder === -2 || rightBorder === -2) return [-1,-1];
// 情况三
if (rightBorder - leftBorder > 1) return [leftBorder + 1, rightBorder - 1];
// 情况二
return [-1, -1];
};
写代码时 多想想有没有更好的实现思路