二分查找(返回查找值的左右邊界索引)

1、返回查找值的隨機索引

  • 搜索區間是 [left, right] 的左閉右閉寫法
int binary_search(int[] nums, int target) {
    int left = 0, right = nums.length - 1; 
    while(left <= right) {
        int mid = left + (right - left) / 2;
        if (nums[mid] < target) {
            left = mid + 1;
        } else if (nums[mid] > target) {
            right = mid - 1; 
        } else if(nums[mid] == target) {
            // 找到該值直接返回其索引
            return mid;
        }
    }
    // 沒有找到
    return -1;
}
  • 搜索區間是 [left, right) 的左閉右開寫法
def binary_search(list_a, target):
    left = 0
    right = len(list_a)
    while left < right:
        mid = (left + right) // 2
        if list_a[mid] == target:
            return mid
        elif list_a[mid] < target:
            left = mid + 1
        elif list_a[mid] > target:
            right = mid
    return -1  # 沒找到

2、返回查找值的左邊界索引

  • 搜索區間是 [left, right] 的左閉右閉寫法
int left_bound(int[] nums, int target) {
    int left = 0, right = nums.length - 1;
    // 搜索區間爲 [left, right]
    while (left <= right) {
        int mid = left + (right - left) / 2;
        if (nums[mid] < target) {
            // 搜索區間變爲 [mid+1, right]
            left = mid + 1;
        } else if (nums[mid] > target) {
            // 搜索區間變爲 [left, mid-1]
            right = mid - 1;
        } else if (nums[mid] == target) {
           // 收縮右側邊界
 // 如果存在target,那right最後必定是target左邊界的位置減1
            right = mid - 1;
        }
    }
    // 檢查出界情況
    // left == right + 1跳出循環
    if (left == nums.length) return -1;
    return nums[left] == target ? left : -1;
}
  • 搜索區間是 [left, right) 的左閉右開寫法
int left_bound(int[] nums, int target) {
    if (nums.length == 0) return -1;
    int left = 0;
    int right = nums.length; // 注意

    while (left < right) { // 注意
        int mid = (left + right) / 2;
        if (nums[mid] == target) {
            right = mid;
        } else if (nums[mid] < target) {
            left = mid + 1;
        } else if (nums[mid] > target) {
            right = mid; // 注意
        }
    }
     // target 比所有數都大
    if (left == nums.length) return -1;
    // 類似之前算法的處理方式
    return nums[left] == target ? left : -1;
}

3、返回查找值的右邊界索引

  • 搜索區間是 [left, right] 的左閉右閉寫法
int right_bound(int[] nums, int target) {
    int left = 0, right = nums.length - 1;
    while (left <= right) {
        int mid = left + (right - left) / 2;
        if (nums[mid] < target) {
            left = mid + 1;
        } else if (nums[mid] > target) {
        // 如果存在target,那right最後就是右邊界
        // 如果不存在target,right是第一個小於target的值
            right = mid - 1;  
        } else if (nums[mid] == target) {
            // 這裏改成收縮左側邊界即可
            left = mid + 1;
        }
    }
// left = right + 1 跳出循環,所以left最大值爲nums_length
// 所以left就不用判斷溢出了
    return nums[left-1] == target ? left-1 : -1;

}
  • 搜索區間是 [left, right) 的左閉右開寫法
int right_bound(int[] nums, int target) {
    if (nums.length == 0) return -1;
    int left = 0, right = nums.length;

    while (left < right) {
        int mid = (left + right) / 2;
        if (nums[mid] == target) {
            left = mid + 1; // 注意
        } else if (nums[mid] < target) {
            left = mid + 1;
        } else if (nums[mid] > target) {
        // 如果存在target, 那right最後是target右邊界加1的位置
            right = mid;
        }
    }
   // left==right時跳出循環, right的最大值爲nums_length
   // 輸出值爲left-1不用判斷溢出
    return nums[left-1] == target ? left-1 : -1;
}

4、總結一下兩種寫法的區別

  1. while裏面的條件用 ‘<’ 還是 '<= '。
  2. right的更新用 ‘mid - 1’ 還是 ‘mid’。
  3. 對於查找左邊界來說無論哪種寫法都需要判斷索引溢出,就算你用right來返回最後值,也要判斷right是否小於0。
  4. 返回隨機索引和右邊界索引不用判斷索引溢出。

5、鳴謝

參考博客在此

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章