部分文章内容为公开资料查询整理,原文出处可能未标注,如有侵权,请联系我,谢谢。邮箱地址:gnivor@163.com ►►►需要气球么?请点击我吧!

LeetCode--33. Search for a Range ,附加153、154、33、81(二分法)

问题33 大意:在一个排好序的数组中寻找target的起始位置。 target在数组中不一定只有一个。结果返回形式int[] {start,end},如果不存在 返回{-1,-1}
要求时间复杂度O(logn)

方法:在数组中找target最左边的位置和最右边的位置,使用二分法.
下面函数为二分法的变体

注意:
1. 考虑当 low == high 时, 我们希望游标往哪里走。
2. 考虑返回的下标,是start、end 还是mid

public static int searchl(int[] nums, int target){
    int len = nums.length;
    int start = 0 ;
    int end = len -1 ;
    int mid = 0 ;
    while(start <= end ){
        mid = (end+start)/2;
        if(nums[mid]<target)
            start = mid+1;  //mid元素小于target,可以令start=mid+1
        else
            end = mid-1 ;
    }    
    if(len==0||start>=len||nums[start]!=target) return -1;
    return start;
    
}

public static int searchr(int[] nums, int target){
    int len = nums.length;
    int start = 0 ;
    int end = len -1 ;
    int mid = 0 ;
    while(start <= end ){
        mid = (end+start)/2;
        if(nums[mid]>target)
            end = mid-1 ;
        else 
            start = mid+1;
    }
    if(len==0||end<0||nums[end]!=target) return -1;
    return end;
    
}

方法体:

public static int[] searchRange(int[] nums, int target) {
    int sl = searchl(nums,target);
    int sr = searchr(nums,target);
    return new int[] {sl,sr};
}

 

153: Find Minimum in Rotated Sorted Array
154: Find Minimum in Rotated Sorted Array II 

第一个问题:给定一个有序数组旋转后的数组,如 (i.e., 0 1 2 4 5 6 7 might become 4 5 6 7 0 1 2).求出数组中最小的数。(数组中无重复元素)

方法:二分法。 start=0 ; end=len-1;
1. mid=(start+end)/2;
2. 如果nums[mid]>nums[start],说明start到mid是递增的,让start=mid;
3. 如果nums[mid]<nums[end],说明mid到end是递减的,让start=mid;
1 2 3循环,直到start+1 = end; 这样start指向的是最大的元素,end指向最小的元素。

 

public static  int findMin(int[] nums) {
    int len = nums.length;
    int start = 0 ; 
    int end = len-1 ;
    if(nums[start]<=nums[end]) //表示单调递增的情况
        return nums[start];
    int mid ;    
    while(start+1<end){
        mid= (start+end)/2;        
        if(nums[mid]>nums[start]){ //若中间的元素大于start元素,令start=min,意思就是start一直往大的数字走
            start = mid;
        }
        else if(nums[mid]<nums[end]){ //若中间的元素小于start元素,令end=min,意思就是end一直往小的数字走
            end = mid;
        }
    }
    //要求的最小元素的位置就在start的下一个,(也就是end) 因为数组是旋转的,所以最大的下一个就是最小的
    return nums[end];
}

另一种方法:

public int findMin(int[] nums) {
    int len = nums.length;
    int start = 0 ; 
    int end = len-1 ;
    int mid ;
    
    while(start<end){
        if(nums[start]<nums[end]){
            return nums[start];
        }
        mid= (start+end)/2;
        if(nums[mid]>=nums[start]){
            start = mid+1;
        }
        else if(nums[mid]<nums[end]){
            end = mid;
        }
    }
    return nums[start];
}

 


第二个问题:类似第一个,只是数组中可能有重复元素。
例如[3,1,3,3,3],这种情形,在第一次循环时 start end mid位置的元素均相同,这样就没有办法判断哪边是递增的哪边是递减的,因此在此情形二分法失效,只能使用顺序搜索。
可以先找到start和end的位置,然后对start和end之间的元素进行顺序搜索。

public static int findMin(int[] nums) {
    int len = nums.length;
    int start = 0;
    int end = len - 1;
    if (nums[start] < nums[end]) // 表示单调递增的情况
        return nums[start];
    int mid = 0;

    while (start + 1 < end) {
        mid = (start + end) / 2;
        if(nums[mid]==nums[start]&&nums[mid]==nums[end]){
            break;
        }
        if (nums[mid] >= nums[start]) {
            start = mid;
        } else if (nums[mid] <= nums[end]) {
            end = mid;
        }        
    }
    if(nums[mid]==nums[start]&&nums[mid]==nums[end]){
        int min = nums[start];
        for(int i = start+1 ; i <=end ; i++){
            if(min>nums[i])
                min = nums[i];
        }
        return min;
    }    
    return nums[end];
}

 也可以使用另一种方法:每次在开始前,将重复的元素跳过。然后按照一般的方法进行即可(注意如果头部和尾部恰好是相同的,如334123333这种情况,只要变成34123即可,因为按照递增的原则,最小值一定在左侧即3-1)。当然也可以加上while(nums[start]==nums[end]) start++;

public static int findMin(int[] nums) {
    int len = nums.length;
    int start = 0;
    int end = len - 1;
    if (nums[start] < nums[end]) // 表示单调递增的情况
        return nums[start];
    int mid = 0;
    while (start + 1 < end) {
        while(start<len-1&&nums[start]==nums[start+1])
            start++;
        while(end>0&&nums[end]==nums[end-1])
            end--;
        mid = (start + end) / 2;

        if (nums[mid] > nums[start]) {
            start = mid;
        } else if (nums[mid] < nums[end]) {
            end = mid;
        }        
    }        

    return nums[end];
}

 

33 Search in Rotated Sorted Array II

public static int search(int[] nums, int target) {
    int len = nums.length;
    if(len==0) return -1;

    int start = 0 ;
    int end = len-1;
    int mid;
    while(start <= end){
        mid = (start+end)/2;
        if(nums[mid]==target)
            return mid;
        if(nums[mid]>=nums[start]){
            if(target>=nums[start]&&target<=nums[mid])
                end = mid-1;
            else
                start = mid+1;
        }
        else if(nums[mid]<=nums[end]){
            if(target>=nums[mid]&&target<=nums[end])
                start = mid+1;
            else    
                end = mid-1;
        }
    }
    return -1;
}
View Code

81 Search in Rotated Sorted Array II

public static boolean search(int[] nums, int target) {
    int len = nums.length;
    if(len==0) return false;

    int start = 0 ;
    int end = len-1;
    int mid;
    while(start <= end){
        while(start<len-1&&nums[start]==nums[start+1])
            start++;
        while(end>0&&nums[end]==nums[end-1])
            end--;
        mid = (start+end)/2;
        if(nums[mid]==target)
            return true;
        if(nums[mid]>=nums[start]){
            if(target>=nums[start]&&target<=nums[mid])
                end = mid-1;
            else
                start = mid+1;
        }
        else if(nums[mid]<=nums[end]){
            if(target>=nums[mid]&&target<=nums[end])
                start = mid+1;
            else    
                end = mid-1;
        }
    }
    return false;
}
View Code

 

 

 

 

posted @ 2015-07-17 20:40  流了个火  阅读(208)  评论(0)    收藏  举报
►►►需要气球么?请点击我吧!►►►
View My Stats