Binary Search 二元搜尋找到重複的值

Binary Search 二元搜尋找到重複的值

說明

如果 array 裡面有重複值,要尋找的 target 就可能有多個答案

索引 0 1 2 3 4 5 6 7 8 9
數字陣列 0 1 2 3 3 3 3 7 8 9
指標位置 指標 指標 指標 指標

因為可能會有多個重複的答案,所以不要一找到數字就直接回傳,不然可能會回傳中間的答案位置,所以必須要 等於 = 回傳答案的判斷式拿掉

最左邊 的答案位置 >= target

在 array 中,找到 >= target 的元素裡面,最小的那個的 index

要找的數字是 3

索引 0 1 2 3 4 5 6 7 8 9
數字陣列 0 1 2 3 3 3 3 7 8 9
指標位置 左指標 右指標

當找到 nums[mid] == target 的時候,由於我們還不確定是否為最左,於是我們繼續把 right 的位置減小,讓 right = mid - 1

索引 0 1 2 3 4 5 6 7 8 9
數字陣列 0 1 2 3 3 3 3 7 8 9
指標位置 左指標 == 右指標

最後因為 左指標右指標 交叉,所以回傳 左指標 為最左邊數字索引

索引 0 1 2 3 4 5 6 7 8 9
數字陣列 0 1 2 3 3 3 3 7 8 9
指標位置 右指標 左指標

若是 中間指標數字 小於 要找的數字 的狀況

索引 0 1 2 3 4 5 6 7 8 9
數字陣列 0 1 2 3 3 3 3 7 8 9
指標位置 左指標 == 右指標

於是我們繼續把 left 的位置增大,讓 left = mid + 1,還是會因為 左指標右指標 交叉,所以回傳 左指標 為最左邊數字索引

索引 0 1 2 3 4 5 6 7 8 9
數字陣列 0 1 2 3 3 3 3 7 8 9
指標位置 右指標 左指標

JavaScript

function BinarySearch(searchNumberArray, searchNumber) {
    // 左側指標
    var leftNumberPointer = 0;
    // 右側指標
    var rightNumberPointer = searchNumberArray.length - 1;
    while (leftNumberPointer <= rightNumberPointer) {
        // 中間指標
        var middleNumberPointer = Math.floor((rightNumberPointer + leftNumberPointer) / 2);
        // 中間指標數字
        var middleNumber = searchNumberArray[middleNumberPointer];

        if (middleNumber >= searchNumber) {
            // 如果「中間指標數字」大於等於「要找的數字」
            // 表示「中間指標」右邊的所有數字都"大於"「要找的數字」
            // 所以將「右側指標」移動到目前「中間指標 - 1」的位置
            rightNumberPointer = middleNumberPointer - 1;
        } else if (middleNumber < searchNumber) {
            // 如果「中間指標數字」小於「要找的數字」
            // 表示「中間指標」左邊的所有數字都"小於"「要找的數字」
            // 所以將「左側指標」移動到目前「中間指標 + 1」的位置
            leftNumberPointer = middleNumberPointer + 1;
        }
    }

    // 如果都沒有找到,回傳最接近的指標
    return leftNumberPointer;
}

TypeScript

function BinarySearch(searchNumberArray: number[], searchNumber: number){
    // 左側指標
    let leftNumberPointer: number = 0;
    // 右側指標
    let rightNumberPointer: number = searchNumberArray.length - 1;

    while (leftNumberPointer <= rightNumberPointer) {
        // 中間指標
        let middleNumberPointer = Math.floor((rightNumberPointer + leftNumberPointer) / 2);
        // 中間指標數字
        let middleNumber = searchNumberArray[middleNumberPointer];

        if (middleNumber >= searchNumber) {
            // 如果「中間指標數字」大於等於「要找的數字」
            // 表示「中間指標」右邊的所有數字都"大於"「要找的數字」
            // 所以將「右側指標」移動到目前「中間指標 - 1」的位置
            rightNumberPointer = middleNumberPointer - 1;
        } else if (middleNumber < searchNumber) {
            // 如果「中間指標數字」小於「要找的數字」
            // 表示「中間指標」左邊的所有數字都"小於"「要找的數字」
            // 所以將「左側指標」移動到目前「中間指標 + 1」的位置
            leftNumberPointer = middleNumberPointer + 1;
        }
    }

    // 如果都沒有找到,回傳最接近的指標
    return leftNumberPointer;
}

最右邊 的答案位置 > target

在 array 中,找到 > target 的元素裡面,最大的那個的 index 右邊的索引

要找的數字是 3

索引 0 1 2 3 4 5 6 7 8 9
數字陣列 0 1 2 3 3 3 3 7 8 9
指標位置 左指標 右指標

當找到 nums[mid] == target 的時候,由於我們還不確定是否為最右,於是我們繼續把 left 的位置增加,讓 left = mid + 1

索引 0 1 2 3 4 5 6 7 8 9
數字陣列 0 1 2 3 3 3 3 7 8 9
指標位置 左指標 == 右指標

最後因為 左指標右指標 交叉,所以回傳 左指標最右邊數字索引 + 1 的位置,將 左指標 - 1 就可以拿到最右邊的答案索引值

索引 0 1 2 3 4 5 6 7 8 9
數字陣列 0 1 2 3 3 3 3 7 8 9
指標位置 右指標 左指標

JavaScript

function BinarySearch(searchNumberArray, searchNumber) {
    // 左側指標
    var leftNumberPointer = 0;
    // 右側指標
    var rightNumberPointer = searchNumberArray.length - 1;
    while (leftNumberPointer <= rightNumberPointer) {
        // 中間指標
        var middleNumberPointer = Math.floor((rightNumberPointer + leftNumberPointer) / 2);
        // 中間指標數字
        var middleNumber = searchNumberArray[middleNumberPointer];

        if (middleNumber > searchNumber) {
            // 如果「中間指標數字」大於等於「要找的數字」
            // 表示「中間指標」右邊的所有數字都"大於"「要找的數字」
            // 所以將「右側指標」移動到目前「中間指標 - 1」的位置
            rightNumberPointer = middleNumberPointer - 1;
        } else if (middleNumber <= searchNumber) {
            // 如果「中間指標數字」小於等於「要找的數字」
            // 表示「中間指標」左邊的所有數字都"小於"「要找的數字」
            // 所以將「左側指標」移動到目前「中間指標 + 1」的位置
            leftNumberPointer = middleNumberPointer + 1;
        }
    }

    // 如果都沒有找到,回傳最接近的指標
    return leftNumberPointer;
}

TypeScript

function BinarySearch(searchNumberArray: number[], searchNumber: number){
    // 左側指標
    let leftNumberPointer: number = 0;
    // 右側指標
    let rightNumberPointer: number = searchNumberArray.length - 1;

    while (leftNumberPointer <= rightNumberPointer) {
        // 中間指標
        let middleNumberPointer = Math.floor((rightNumberPointer + leftNumberPointer) / 2);
        // 中間指標數字
        let middleNumber = searchNumberArray[middleNumberPointer];

        if (middleNumber > searchNumber) {
            // 如果「中間指標數字」大於「要找的數字」
            // 表示「中間指標」右邊的所有數字都"大於"「要找的數字」
            // 所以將「右側指標」移動到目前「中間指標 - 1」的位置
            rightNumberPointer = middleNumberPointer - 1;
        } else if (middleNumber <= searchNumber) {
            // 如果「中間指標數字」小於等於「要找的數字」
            // 表示「中間指標」左邊的所有數字都"小於"「要找的數字」
            // 所以將「左側指標」移動到目前「中間指標 + 1」的位置
            leftNumberPointer = middleNumberPointer + 1;
        }
    }

    // 如果都沒有找到,回傳最接近的指標
    return leftNumberPointer;
}

參考資料