为了跑路而进行的算法day1

24 阅读3分钟

今日进度:代码随想录 二分法

  • 704. 二分查找
  • 35.搜索插入位置
  • 34.在排序数组中查找元素的第一个和最后一个位置
  • 69.x 的平方根
  • 367.有效的完全平方数
  1. 二分法计算要从一开始就确定要用左闭右闭区间还是左闭右开区间
  • 左闭右闭区间: 取中点后,移动边界时,right要移动到mid-1left要移动到mid+1(因为mid是错误值才会移动区间,移动完的区间依然是两端都可以取值的)
  • 左闭右开区间: 取中点后,移动边界时,right要移动到midleft要移动到mid+1(因为mid是错误值才会移动区间,移动完的区间右边界不取,要取左边界)
  1. 二分法的mid要用mid = left + Math.floor((right - left) / 2)的方式来定义。(防止溢出:如果使用(left + right) / 2的方式来计算mid,在leftright都是很大的整数时,它们的和可能会导致整数溢出。使用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];
};

写代码时 多想想有没有更好的实现思路