二分查找模板(查找数、左边界、右边界)

二分查找模板(查找数、左边界、右边界)

在这里插入图片描述

Although the basic idea of binary search is comparatively straightforward, the details can be surprisingly tricky...

二分查找框架

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

查找一个数val

int binarySearch(int[] nums, int val) {
    
    
	int left = 0;
    int right = nums.length - 1;    //☚☚☚
    
	while(left <= right) {
    
              //☚☚☚
		int mid = left + (right - left) / 2;
		if(nums[mid] == val) {
    
    
			return mid;       //☚☚☚
		}else if(nums[mid] < val) {
    
    
			left = mid + 1;
		}else if(nums[mid] > val) {
    
    
			right = mid - 1;
		}
	}
	return -1;
}

此算法的缺陷

  • 若要在[1, 2, 2, 2, 3]中查找2,则返回的下标为2
  • 若为第一个则是下标1
  • 若为最后一个则是下标3

查找一个数val(返回第一次出现的下标)

方法一:

int binarySearch(int[] nums, int val) {
    
    
    if(nums == null || 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] == val) {
    
    
			right = mid - 1;   //☚☚☚
		}else if(nums[mid] < val) {
    
    
			left = mid + 1;
		}else if(nums[mid] > val) {
    
    
			right = mid - 1;
		}
	}
	return right + 1;   //☚☚☚
}

简化代码为

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

方法二:

int binarySearch(int[] nums, int val) {
    
    
	if(nums == null || nums.length == 0) return -1;
	int left = 0;
	int right = nums.length;   //☚☚☚

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

查找一个数val(返回最后一次出现的下标)

方法一:

int binarySearch(int[] nums, int val) {
    
    
    if(nums == null || 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] == val) {
    
    
			left = mid + 1;   //☚☚☚
		}else if(nums[mid] < val) {
    
    
			left = mid + 1;
		}else if(nums[mid] > val) {
    
    
			right = mid - 1;
		}
	}
	return left - 1;  //☚☚☚
}

简化代码为

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

方法二:

int binarySearch(int[] nums, int val) {
    
    
	if(nums == null || nums.length == 0) return -1;
	int left = 0;
	int right = nums.length;   //☚☚☚
		
	while(left < right) {
    
          //☚☚☚
		int mid = left + (right - left) / 2;
		if(nums[mid] == val) {
    
    
			left = mid + 1;   //☚☚☚
		}else if(nums[mid] < val){
    
    
			left = mid + 1;   
		}else if(nums[mid] > val){
    
    
			right = mid;      //☚☚☚
		}
	}
	return left - 1;    //☚☚☚
}

左边界(返回小于val的最大值的下标)

查找一个数(返回第一次出现的下标)思路一样,

找到第一次出现的下标right + 1后,下标right处就是小于它的最大值

int binarySearch(int[] nums, int val) {
    
    
    if(nums == null || 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] == val) {
    
    
			right = mid - 1;   
		}else if(nums[mid] < val) {
    
    
			left = mid + 1;
		}else if(nums[mid] > val) {
    
    
			right = mid - 1;
		}
	}
	return right;   //☚☚☚
}

右边界(返回大于val的最小值的下标)

查找一个数(返回最后一次出现的下标)思路一样,

找到最后一次出现的下标left - 1后,下标left处就是大于它的最小值

int binarySearch(int[] nums, int val) {
    
    
    if(nums == null || 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] == val) {
    
    
			left = mid + 1;   
		}else if(nums[mid] < val) {
    
    
			left = mid + 1;
		}else if(nums[mid] > val) {
    
    
			right = mid - 1;
		}
	}
	return left;  //☚☚☚
}

上述代码while循环中分情况写全是为了便于理解,看懂就好,是否化简看个人喜好啦~

相关参考链接:

labuladong二分查找算法详解:https://mp.weixin.qq.com/s/uA2suoVykENmCQcKFMOSuQ
二分模板大全:https://blog.csdn.net/vocaloid01/article/details/82257336

猜你喜欢

转载自blog.csdn.net/weixin_44368437/article/details/112676263