LeetCode二分查找問題全集

二分查找框架

int binarySearch(int[] nums, int target) {
    int left = 0, right = ...;

    while(...) {
        int mid = left + (right - left) / 2;
        if (nums[mid] == target) {
            ...
        } else if (nums[mid] < target) {
            left = ...
        } else if (nums[mid] > target) {
            right = ...
        }
    }
    return ...;
}

分析二分查找的一個技巧是:不要出現 else,而是把所有情況用 else if 寫清楚,這樣可以清楚地展現所有細節

計算 mid 時需要防止溢出,代碼中 left + (right - left) / 2 就和 (left + right) / 2 的結果相同,但是有效防止了 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;
}

int left_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) {
            right = mid - 1;
        } else if (nums[mid] == target) {
            // 別返回,鎖定左側邊界
            right = mid - 1;
        }
    }
    // 最後要檢查 left 越界的情況
    if (left >= nums.length || nums[left] != target)
        return -1;
    return left;
}


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) {
            right = mid - 1;
        } else if (nums[mid] == target) {
            // 別返回,鎖定右側邊界
            left = mid + 1;
        }
    }
    // 最後要檢查 right 越界的情況
    if (right < 0 || nums[right] != target)
        return -1;
    return right;
}

704. 二分查找

class Solution {
    public int search(int[] nums, int target) {
        int left = 0;
        int 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;
    }
}

33. 搜索旋轉排序數組

class Solution {
    public int search(int[] nums, int target) {
        int left = 0;
        int right = nums.length-1;
        while(left<=right){
            int mid = left+(right-left)/2;
            if(nums[mid]==target){
                return mid;
            }

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

81. 搜索旋轉排序數組 II

class Solution {
    public boolean search(int[] nums, int target) {
        int left = 0;
        int right = nums.length - 1;
        while(left<=right){
            int mid = left + (right-left)/2;
            if(nums[mid]==target){
                return true;
            }
            if(nums[mid]>nums[left]){
                if(nums[mid]>=target&&nums[left]<=target){
                    right = mid -1;
                }else{
                    left = mid + 1;
                }
            }else if(nums[mid]<nums[left]){
                if(nums[mid]<=target&&nums[right]>=target){
                    left = mid + 1;
                }else{
                    right = mid - 1;
                }
            }else{
                left++;
            }
        }
        return false;
    }
}

153. 尋找旋轉排序數組中的最小值

class Solution {
    public int findMin(int[] nums) {
        int left = 0;
        int right = nums.length - 1;
        while(left<=right){
            int mid = left + (right-left)/2;
            if(nums[mid]>nums[right]){
                left = mid + 1;
            }else if(nums[mid]<nums[right]){
                right = mid;
            }else{
                right = mid - 1;
            }
        }
        return nums[left];
    }
}

154. 尋找旋轉排序數組中的最小值 II

class Solution {
    public int findMin(int[] nums) {
        int left = 0;
        int right = nums.length - 1;
        while(left<=right){
            int mid = left + (right-left)/2;
            if(nums[mid]>nums[right]){
                left = mid + 1;
            }else if(nums[mid]<nums[right]){
                right = mid;
            }else{
                right--;
            }
        }
        return nums[left];
    }
}

300. 最長上升子序列

class Solution {
    public int lengthOfLIS(int[] nums) {
        int[] tails = new int[nums.length];
        int res = 0;
        for(int num : nums) {
            int left = 0, right = res;
            while(left < right) {
                int mid = (left + right) / 2;
                if(tails[mid] < num) left = mid + 1;
                else right = mid;
            }
            tails[left] = num;
            if(res == right) res++;
        }
        return res;
    }
}

275. H指數 II

class Solution {
    public int hIndex(int[] citations) {
        int len = citations.length;
        if(len==0||citations[len-1]==0){
            return 0;
        }

        int left = 0;
        int right = len-1;
        while(left<right){
            int mid = left + (right-left)/2;
            //區間 [mid, len - 1] 的長度,即 len - 1 - mid + 1 = len - mid
            if(citations[mid]<len - mid){
                left = mid + 1;
            }else{
                right = mid;
            }
        }
        return len-left;
    }
}

34. 在排序數組中查找元素的第一個和最後一個位置

class Solution {
    public int[] searchRange(int[] nums, int target) {
        int left = 0;
        int right = nums.length - 1;
        int FirstPosition = findFirstPosition(nums,target);
        if(FirstPosition==-1){
            return new int[]{-1,-1};
        }
        int LastPosition = findLastPosition(nums,target);
        return new int[]{FirstPosition,LastPosition};
    }

    private int findFirstPosition(int[] nums,int target){
        int left = 0;
        int right = nums.length - 1;
        while(left<=right){
            int mid = left + (right-left)/2;
            //尋找開始位置
            if(nums[mid]>target){
                right = mid - 1;
            }else if(nums[mid]<target){
                left = mid + 1;
            }else if(nums[mid]==target){
                right = mid - 1;
            }
        }
        // 最後要檢查 left 越界的情況
        if (left >= nums.length || nums[left] != target)
            return -1;
        return left;
    }

    private int findLastPosition(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) {
                // 別返回,鎖定右側邊界
                left = mid + 1;
            }
        }
        // 最後要檢查 right 越界的情況
        if (right < 0 || nums[right] != target)
            return -1;
        return right;
    }
}

1095. 山脈數組中查找目標值

class Solution {
    public int findInMountainArray(int target, MountainArray mountainArr) {
        int size = mountainArr.length();
        int Mountaintop = findMountaintop(mountainArr,0,size-1);
        int res = findFromSortedArr(mountainArr,target,0,Mountaintop);
        if(res!=-1){
            return res;
        }
        res = findFromInversedArr(mountainArr,target,Mountaintop+1,size-1);
        return res;
    }

    private int findMountaintop(MountainArray mountainArr,int l,int r){
        while(l<r){
            int mid = l + (r - l)/2;
            if(mountainArr.get(mid)<mountainArr.get(mid+1)){
                l = mid+1;
            }else{
                r = mid;
            }
        }
        return l;
    }

    private int findFromSortedArr(MountainArray mountainArr,int target,int l,int r){
        while(l<r){
            int mid = l + (r-l)/2;
            if(target==mountainArr.get(mid)){
                return mid;
            }else if(mountainArr.get(mid)<target){
                l = mid + 1;
            }else{
                r = mid;
            }
        }
        if (mountainArr.get(l) == target) {
            return l;
        }
        return -1;
    }
    private int findFromInversedArr(MountainArray mountainArr,int target,int l,int r){
        while(l<r){
            int mid = l + (r-l)/2;
            if(target==mountainArr.get(mid)){
                return mid;
            }else if(mountainArr.get(mid)>target){
                l = mid + 1;
            }else{
                r = mid;
            }
        }
        if (mountainArr.get(l) == target) {
            return l;
        }
        return -1;
    }
}

4. 尋找兩個有序數組的中位數

69. x 的平方根

class Solution {
    public int mySqrt(int x) {
        long left = 0;
        // # 爲了照顧到 1 把右邊界設置爲 x // 2 + 1
        long right = x / 2 + 1;
        while (left < right) {
            // 注意:這裏一定取右中位數,如果取左中位數,代碼會進入死循環
            long mid = left + (right - left + 1) / 2;
            if (mid * mid > x) {
                right = mid - 1;
            } else {
                left = mid;
            }
        }
        return (int) left;
    }
}

374. 猜數字大小

class Solution extends GuessGame {
    public int guessNumber(int n) {
        int low = 1;
        int high = n;
        while (low <= high) {
            int mid = low + (high - low) / 2;
            int res = guess(mid);
            if (res == 0)
                return mid;
            else if (res < 0)
                high = mid - 1;
            else
                low = mid + 1;
        }
        return -1;
    }
}

你知道的越多,你不知道的越多。
有道無術,術尚可求,有術無道,止於術。
如有其它問題,歡迎大家留言,我們一起討論,一起學習,一起進步

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