有趣的二分

有趣的算法

对算法一直很陌生, 以后也会很陌生, 因为我是程序员,而不是数学家或者算法工程师
可这阻止不了算法的有趣.

先有了 快慢指针,让人眼前一亮, 而后这里的二分方法又让人 一个激动

二分的方法很简单, 上来就是去找你的 一半 去, 快速定位.

整理的复杂度也会跟 快速排序等方法有得一拼.

二分的关键, 是找到中间 的, 然后对中间的进行目标比较, 然后继续中间划分

这个获取中间的场景随着头尾的变动, 所以也是变动的. 我们要跟随着使用的场景去修改头尾

比较经典的场景就是去寻找一个数的插入位置. 这里有一个数字, 这里有一个数字, 我需要快速的找到这个数字应该插入的位置

//这个数组是假定已经排好顺序的, 这样这个二分才有意义
//定义好左右位置
//const target = 3.5
const arr = [1,2,3,4,5]

let l = arr.length;
let i = 0, // 最左侧的位置
    j = l - 1; //最右侧的位置
let mid = i + Math.floor((j-i)/2) // 或者可以使用位移 (j-i)>>1

let ret = l; //暂定我们要返回的就是最后一个点

//直接选择中间的位置进行比较,

arr[mid] > target
//如果中间的位置的数值比目标大, 那么数值肯定在中间以左, 我们需要修改右侧的位置(相对的mid也会变动)
j = mid - 1;

//如果相等, 那么正好, 我们要的目标就是这个地方
ret = mid;

//同理, 如果中间的位置小, 那么数字肯定在中间以右, 我们需要修改左侧的位置
i = mid + 1

//step2:
//因为正常情况下, 我们认为我们的元素是从小到大金星排列的, 所以正常的时候, 插入位置在右侧(>=)
//所以上边的判断可以合并

arr[mid] >= target
ret = mid
j = mid -1

//每次修改后, 我们需要重新计算 `mid`, 所以我们将方法进行整理后 ,如下

//左侧索引小于右侧, i = j, 也可以, 代表我们的遍历还是有元素的
while (i <= j) {
    let mid = i + Math.floor((j-i)/2);
    if (arr[mid] >= target) {
        ret = mid;
        j = mid - 1;
    }
    else {
        i = mid + 1
    }
}


//step3: 我们整理成完整的方法

function findPosition(arr, target) {
    let l = arr.length;
    let i = 0, // 最左侧的位置
    j = l - 1; //最右侧的位置
    let ret = l;
    while (i <= j) {
        let mid = i + Math.floor((j-i)/2);//可以使用位移的方法, >>
        let mid = i + (j-i>>1); //注意运算符优先级 位移操作的优先级是小于 + - 的
        if (arr[mid] >= target) {
            ret = mid;
            j = mid - 1;
        }
        else {
            i = mid + 1
        }
    }

    return ret;

}

原文地址:https://www.cnblogs.com/asdfq/p/13338245.html