二分查找小结
在做leetcode二分查找类型题目时写while条件总担心写错,也确实好几次都是得到Wrong Answer之后再修改对的。在做Search for a range一题时,虽然被Accept了,但看网上其他同学的解析并不是特别理解,终于下决心去好好研究下最经典的二分查找算法,搞清楚不同情况下为什么while条件写法不一样。很幸运,很快便找到一遍总结得很棒的博客:
http://blog.csdn.net/daniel_ustc/article/details/17307937
拜读后自己实现了下,实现过程中对while条件不同情况下为什么不一样理解得更深刻了。
实现的三个二分查找方法分别解决如下问题:
1)查找数组中target出现的下标,不存在返回-1
2)查找数组中target第一次出现的下标位置,若不存在返回-1
3)查找数组中target最后一次出现的下标位置,若不存在返回-1
PS: 数组升序排列,可能有重复元素
1 package org.work.basic.binarysearch; 2 3 import junit.framework.Assert; 4 import org.junit.Test; 5 6 public class BinarySearchCore { 7 8 @Test 9 public void testBinarySearch() { 10 int[] nums = {0,1,1,1,2}; 11 Assert.assertEquals(2, binarySearch(nums, 1)); 12 Assert.assertEquals(1, binarySearchFirst(nums, 1)); 13 Assert.assertEquals(3, binarySearchLast(nums, 1)); 14 int[] nums1 = {1}; 15 Assert.assertEquals(0, binarySearch(nums1, 1)); 16 Assert.assertEquals(0, binarySearchFirst(nums1, 1)); 17 Assert.assertEquals(0, binarySearchLast(nums1, 1)); 18 int[] nums2 = {1,1}; 19 Assert.assertEquals(0, binarySearch(nums2, 1)); 20 Assert.assertEquals(0, binarySearchFirst(nums2, 1)); 21 Assert.assertEquals(1, binarySearchLast(nums2, 1)); 22 23 } 24 // 查找target在nums[]中的下标,若有重复,返回任意一个即可,若找不到返回 -1 25 public int binarySearch(int[] nums, int target) { 26 if (nums == null || nums.length == 0) 27 return -1; 28 int left = 0, right = nums.length - 1; 29 int mid = 0; 30 while (left <= right) { 31 mid = left + ((right - left) >> 1); 32 if (target == nums[mid]) 33 return mid; 34 else if (target < nums[mid]) 35 right = mid - 1; 36 else 37 left = mid + 1; 38 } 39 return -1; 40 } 41 // 查找target在nums[]中第一次出现的下标,若找不到返回-1 42 public int binarySearchFirst(int[] nums, int target) { 43 if (nums == null || nums.length == 0) 44 return -1; 45 int left = 0, right = nums.length - 1; 46 int mid = 0; 47 while (left < right) { // 此处不能有等号,否则可能在right=mid处死循环,考虑case:[1], 1 48 mid = left + ((right - left) >> 1); 49 if (target > nums[mid]) 50 left = mid + 1; 51 else 52 right = mid; 53 } 54 if (nums[left] == target) 55 return left; 56 return -1; 57 } 58 // 查找target在nums[]中最后一次出现的下标,若找不到返回-1 59 public int binarySearchLast(int[] nums, int target) { 60 if (nums == null || nums.length == 0) 61 return -1; 62 int left = 0, right = nums.length - 1; 63 int mid = 0; 64 while (left + 1 < right) { // 循环只处理元素个数大于两个的情况,两个以下元素时可能在left=mid处死循环(两个元素时left==mid),考虑case:[1,1],1 65 mid = left + ((right - left) >> 1); 66 if (target < nums[mid]) 67 right = mid - 1; 68 else 69 left = mid; 70 } 71 if (nums[right] == target) 72 return right; 73 else if(nums[left] == target) 74 return left; 75 return -1; 76 } 77 }