二分查找总结

在《编程之美》中有一组关于二分查找的题目,给定一个有序(不降序)数组arr和一个数字v:

1、求任意一个i,使得arr[i]等于v,不存在则返回-1。

2、求最小的一个i,使得arr[i]等于v,不存在则返回-1。

3、求最大一个i,使得arr[i]等于v,不存在则返回-1。

4、求最大的i,使得arr[i]小于v,不存在则返回-1。

5、求最小的i,使得arr[i]大于v,不存在返回-1。


第一个题目最常见,也是最经典的二分查找,对于这个题目,while循环条件可以设置为 min <= max ,在循环内部如果arr[mid]==v,就返回mid,跳出了while就表示没找到。另外,对min和max的更改都可以通过使mid加一或者减一得到。代码如下:

	//在数组a中,寻找任何一个i,使a[i]等于x
	public int findAnyEqual(int[] a,int x){
		return binarySearchForAnyEqual(a, 0, a.length-1, x);
	}
	public int binarySearchForAnyEqual(int[] a,int s,int e,int val){
		int min = s,max = e;
		int mid;
		while(min<=max){
			mid = min+(max-min)/2;
			if(a[mid]==val){
				return mid;
			}else if(a[mid]>val){
				max = mid-1;
			}else{
				min = mid+1;
			}
		}
		return -1;	//跳出while循环就表示没有找到
	}

对于 第二三个题目,思路是一样的,二三题要考察的是如何处理存在多个相同值的情况,即如果数组中如果存在多个v,我们该怎么办,因为是要找最大的一个,我们在遇到 arr[mid]==v 的时候,可以跟处理arr[mid]<v是一样的,此外还需要注意的是,while循环的条件设置为 min < max-1,这样循环停止的时候min==max-1,我们可以分别比较min和max是否等于v,在while循环里更改min和max值的时候可以令 min = mid,max=mid,而不令mid加一或者减一。第二三题代码如下:

	//在一个非降序的数组中,寻找a[i]等于x,若存在多个i,返回最大的一个,不存在返回-1
	public int findMaxEqual(int[] a,int x){
		return binarySearchForMaxEqual(a, 0, a.length-1, x);
	}
	public int binarySearchForMaxEqual(int[] a,int s,int e,int val){
		
		int min=s,max=e;
		int mid;
		
		while(min<max-1){
			mid = min+(max-min)/2;
			if(a[mid]<=val){
				min = mid;
			}else{
				max = mid;
			}
		}
		if(a[max]==val){
			return max;
		}else if(a[min]==val){
			return min;
		}
		return -1;
	}
	
	//在一个非降序的数组中,寻找a[i]等于x,如果有多个i,返回最小的一个,不存在返回-1
	public int findMinEqual(int[] a,int x){
		return binarySearchForMinEqual(a, 0, a.length-1, x);
	}
	public int binarySearchForMinEqual(int[] a,int s,int e,int val){
		int min = s, max = e;
		int mid;
		while(min<max-1){
			mid = min + (max-min)/2;
			if(a[mid]>=val){
				max = mid;
			}else{
				min = mid;
			}
		}
		
		if(a[min]==val){
			return min;
		}else if(a[max]==val){
			return max;
		}
		return -1;
	}

后面两个题的思路跟第二三题是一样的,同样要考虑存在多个值相等的情况,所以while循环条件设置为 min<max-1,然后循环结束的时候min==max-1,此时我们可能找到v,也可能没有找到v。 以第四个题为例,如果没有找到v,那么arr[min]一定小于v,arr[max]一定大于v,如果找到了v,那么arr[max]一定等于v,还需要考察arr[min],代码如下:

	//在数组a中,寻找小于x的最大元素,返回其下标
	public int findMaxElementLessThan(int[] a,int x){
		return binarySearchForMaxElementLessThan(a, 0, a.length-1, x);
	}
	public int binarySearchForMaxElementLessThan(int[] a,int s,int e,int val){
		int min = s,max = e;
		int mid;
		
		while(min<max-1){
			mid = min+(max-min)/2;
			if(a[mid]>=val){	//大于跟等于同等处理
				max = mid;
			}else{
				min = mid;
			}
		}
		
		if(a[min]==val){
			if(min==0){
				return -1;
			}else{
				return min-1;
			}
		}
		return min;
	}
	
	//寻找最小的i,使a[i]大于 x
	public int findMinElementGreatThan(int[] a,int x){
		return binarySearchForMinElementGreatThan(a, 0, a.length-1, x);
	}
	public int binarySearchForMinElementGreatThan(int[] a,int s,int e,int val){
		int min = s,max = e;
		int mid;
		while(min<max-1){
			mid = min+(max-min)/2;
			if(a[mid]<=val){	//对小于的处理跟等于一样	
				min = mid;
			}else{
				max = mid;
			}
		}
		if(a[max]==val){
			if(max==a.length-1){
				return -1;
			}
			return max+1;
		}
		return max;
	}

测试代码:

	public static void main(String[] args) {
		Solution s = new Solution();
		//         0 1 2 3 4 5 6 7 8 9 10 11 12
		int[] a = {1,2,2,2,3,3,3,5,6,7,7,7,8};
		
		System.out.println(s.findMinElementGreatThan(a, 1));
	}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值