LeetCode 二分法细节,踩坑记录

1.传统二分,在排序数组中找某个数:[0,nums.length] 左右都闭区间

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    return mid;
}
return -1;

 

2.在一个允许重复的排序数组里找某个数的最左边界。 eg. [1,2,3,3,3,3,4]    3的最左index=2。这个时候用开区间,遇到相等的右区间往左边缩放。最后还需要判断下 nums[left] == target,因为可能找不到。

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

3.在一个允许重复的排序数组里找某个数的最右边界。 eg. [1,2,3,3,3,3,4]    3的最左index=5。这个时候用开区间,遇到相等的右区间往右边缩放。最后中止条件会使得left=right,需要返回right-1或者left-1。此外最后还需要判断下 nums[right] == target,因为可能找不到。

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

4.LeetCode33 搜索旋转排序数组

旋转数组的问题分为两种:带重复的和不带重复的。这一题是不带重复的,都用闭区间。

判断逻辑:看nums[left]<=nums[mid]是不是成立(必须有等号,因为当有偶数个时候,mid取两个中间数的前一个,区间长度为2的时候会造成left=mid)。

1.如果左边是递增的

          - 如果在左边递增的范围里:选左边 right = mid -1

          - 如果非左边递增范围:只能在右边 left = mid + 1

2.如果左边不是递增的(只能右边递增)

          - 如果在右边的递增范围里:选右边 left = mid + 1

          - 如果非右边递增范围:只能左边 right = left + 1

class Solution {
    public int search(int[] nums, int target) {
        if(nums.length == 0)    return -1;
        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(target >= nums[left] && target < nums[mid])
                    right = mid-1;
                else    left = mid + 1;
            }

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

        return -1;
    }
}

5.LeetCode81 搜索旋转排序数组 II

带重复的旋转数组,思路与上一题一摸一样,除了加一句相等时候的判断。

class Solution {
    public boolean search(int[] nums, int target) {
        if(nums.length == 0 )   return false;
        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[left] < nums[mid]){
                if(nums[left] <= target && nums[mid] >target)   right = mid - 1;
                else    left = mid + 1;
            }
            else if (nums[left] == nums[mid]){   //加这里,如果左半部分不知道是否升序,就left++
                left++;
            }
            else{
                if(nums[right] >= target && nums[mid] < target)     left = mid + 1;
                else    right = mid -1;
            }
        }

        return false;
    }
}

 

你可能感兴趣的:(LeetCode)