十五周算法训练营——二分查找

今天是十五周算法训练营的第二周,主要讲二分搜索,包含:二分搜索一个数、寻找左侧边界的二分搜索、寻找右侧边界的二分搜索。(欢迎加入十五周算法训练营,与小伙伴一起卷算法)

二分搜索一个数

/**
 * 寻找一个数(基本的二分搜索)
 */

function binarySearch(nums, target) {
    let left = 0;
    // 此处赋值为最后的索引,再结合while判断条件,搜索区间是个闭区间,为[left, right]
    let right = nums.length - 1;

    // 此处比较符号是<=,这是因为若为<,则终止的时候会有一个数,该数没有做比较,会出问题
    // 此时终止条件是left == right + 1
    while (left <= right) {
        // let mid = left + parseInt((right - left) / 2, 10);
        let mid = parseInt((left + right) / 2, 10);
        if (nums[mid] === target) {
            return mid;
        } else if (nums[mid] > target) {
            right = mid - 1;
        } else if (nums[mid] < target) {
            left = mid + 1;
        }
    }

    return -1;
}

const nums = [1, 2, 3, 4, 5];
const target = 4;

console.log(binarySearch(nums, target));

寻找左侧边界的二分搜索

/**
 * 寻找左侧边界的二分搜索
 */

// 这种方式取的区间是[left, right),即左闭右开区间
function leftBound1(nums, target) {
    if (nums.length === 0) {
        return -1;
    }

    let left = 0;
    let right = nums.length;

    // 此时终止条件是left == right
    // 每次循环的搜索区间是[left, right)
    while (left < right) {
        let mid = parseInt((left + right) / 2, 10);
        if (nums[mid] === target) {
            // 该算法能够搜索左边界的原因是其在遇到nums[mid] == target时不会立即返回,而是缩小搜索区间的上界right,在区间[left, mid)中继续搜索,即不断向左收缩,达到锁定左侧边界的目的
            right = mid;
        } else if (nums[mid] < target) {
            left = mid + 1;
        } else if (nums[mid] > target) {
            right = mid;
        }
    }

    // 如果target比所有数都大,此时返回的索引将会是nums.length则证明没找到,返回-1
    if (left === nums.length) {
        return -1;
    }

    // 如果找到的数比所有的都小,将会返回索引为0,此时需要进行判断索引为0时是否是target值
    return nums[left] === target ? left : -1;
}

const nums = [1, 2, 2, 2, 3];
const target = 2;
console.log(leftBound1(nums, target));

// 这种方式取的区间是[left, right]
function leftBound2(nums, target) {
    let left = 0;
    let right = nums.length - 1;

    while (left <= right) {
        const mid = parseInt((left + right) / 2, 10);

        if (nums[mid] === target) {
            right = mid - 1;
        } else if (nums[mid] > target) {
            right = mid - 1;
        } else if (nums[mid] < target) {
            left = mid + 1;
        }
    }

    if (left >= nums.length || nums[left] !== target) {
        return -1;
    }

    return left;
}

const nums2 = [1, 2, 2, 2, 3];
const target2 = 2;
console.log(leftBound2(nums2, target2));

寻找右侧边界的二分搜索

/**
 * 寻找右侧边界的二分查找
 */

// 这种方式取的区间是[left, right)
function rightBound1(nums, target) {
    if (nums.length === 0) {
        return -1;
    }
    let left = 0;
    let right = nums.length;

    while (left < right) {
        const mid = parseInt((left + right) / 2, 10);

        if (nums[mid] === target) {
            left = mid + 1;
        } else if (nums[mid] < target) {
            left = mid + 1;
        } else if (nums[mid] > target) {
            right = mid;
        }
    }

    return left - 1;
}

const nums1 = [1, 2, 2, 2, 3];
const target1 = 2;
console.log(rightBound1(nums1, target1));

// 这种方式取的区间是[left, right]
function rightBound2(nums, target) {
    let left = 0;
    right = nums.length - 1;

    while (left <= right) {
        const mid = parseInt((left + right) / 2, 10);

        if (nums[mid] === target) {
            left = mid + 1;
        } else if (nums[mid] < target) {
            left = mid + 1;
        } else if (nums[mid] > target) {
            right = mid - 1;
        }
    }

    if (right < 0 || nums[right] !== target) {
        return -1;
    }

    return right;
}

const nums2 = [1, 2, 2, 2, 3];
const target2 = 2;
console.log(rightBound2(nums2, target2));

十五周算法训练营——二分查找_第1张图片

你可能感兴趣的:(算法,javascript,数据结构,开发语言,ecmascript)