BinarySearch题目汇总:
- temp笔记?:
二分搜索题暂时分两种情况:
case1:找到了就OK——while循环中要写return,如果跳出循环,说明一定没找到;
case2:必须“遍历”完整个数组才能得出结果——while循环中没有return,循环结束,给出结果(找到/没找到都可能)
一 普通二分搜索
LintCode 457. Classical BInary Search
public class Solution {
/**
* @param nums: An integer array sorted in ascending order
* @param target: An integer
* @return: An integer
*/
public int findPosition(int[] nums, int target) {
int lo = 0, hi = nums.length-1;
while(lo <= hi) {
int mid = lo + (hi-lo)/2;
if(nums[mid] == target) //如果找到了,则返回
return mid;
if(nums[mid] > target)
hi = mid - 1;
else
lo = mid + 1;
}
return -1; //跳出循环,一定没找到
}
}
二 查找满足条件的第一个位置
LintCode 14. First Position of Target
public class Solution {
/**
* @param nums: The integer array.
* @param target: Target to find.
* @return: The first position of target. Position starts from 0.
*/
public int binarySearch(int[] nums, int target) {
// write your code here
int lo = 0, hi = nums.length-1;
while(lo <= hi) {
int mid = lo + (hi-lo)/2;
if(nums[mid] >= target) //注:此处条件设置成nums[i]>=target而不是==target
hi = mid - 1;
else
lo = mid + 1;
}
return nums[lo] == target ? lo : -1; //while循环结束后,nums[lo]是第一个>=target的数,再判断它是否满足条件
}
}
相似题目a:
LintCode 74. First Bad Version
LeetCode 278. First Bad Version
public int findFirstBadVersion(int n) {
// write your code here
int lo = 1, hi = n;
while(lo <= hi) {
int mid = lo + (hi-lo)/2;
if(SVNRepo.isBadVersion(mid))
hi = mid - 1;
else
lo = mid + 1;
}
return lo;
}
相似题目b:
LintCode 60. Search Insert Position
class Solution {
public int searchInsert(int[] nums, int target) {
//如果找到target,立刻返回其位置;
//否则,寻找数组中第一个大于target的元素的位置,就是target的插入位置
int lo = 0, hi = nums.length-1;
while(lo <= hi) {
int mid = lo + (hi-lo)/2;
if(nums[mid] == target)
return mid;
if(nums[mid] > target)
hi = mid - 1;
else
lo = mid + 1;
}
return lo;
}
}
三 查找满足条件的最后一个位置
tip:也可以改为“查找不满足条件的第一个位置”,则和二 查找满足条件的第一个位置相同思路。
LintCode 458. Last Position of Target
public int lastPosition(int[] nums, int target) {
// write your code here
int lo = 0, hi = nums.length-1;
while(lo <= hi) {
int mid = lo + (hi-lo)/2;
if(nums[mid]<=target)
lo = mid + 1;
else
hi = mid - 1;
}
//此时,hi是满足条件nums[i]<=target的最后一个位置,取值可能为-1和0,1,...,n-1.
if(hi < 0) return -1; //hi = -1说明所有元素均大于target
return nums[hi] == target ? hi : -1; //nums[hi]是<=target的最后一个元素,要判断是否==target
}
相似题目:
LeetCode 34. 在排序数组中查找元素的第一个和最后一个位置
class Solution {
public int[] searchRange(int[] nums, int target) {
int[] ans = {-1,-1};
//查找nums[i]>=target的第一个位置:
int lo = 0, hi = nums.length-1;
if(hi < 0) return ans;
while(lo <= hi) {
int mid = lo + (hi-lo)/2;
if(nums[mid] >= target)
hi = mid - 1;
else
lo = mid + 1;
}
//此时 nums[lo]为>=target的第一个位置,但不保证==target
if(lo == nums.length || nums[lo] != target) return ans; //target不存在
ans[0] = lo; //否则 target一定存在
//查找nums[i] <= target的最后一个位置:
hi = nums.length-1; //此时lo指向target出现的第一个位置,不用动
while(lo <= hi) {
int mid = lo + (hi-lo)/2;
if(nums[mid] <= target)
lo = mid + 1;
else
hi = mid - 1;
}
//此时 nums[hi]为<=target的最后一个位置,且已知target一定存在
ans[1] = hi;
return ans;
}
}
四 变形题目
LintCode 75. Find Peak Element 寻找峰值
public class Solution {
/**
* @param A: An integers array.
* @return: return any of peek positions.
*/
public int findPeak(int[] A) {
// write your code here
int lo = 1, hi = A.length-2; //【注意:mid不能取到数组的第一个或是最后一个元素】
while(lo <= hi) {
int mid = lo + (hi-lo)/2;
if(A[mid-1] < A[mid] && A[mid] > A[mid+1])
return mid;
if(A[mid-1] < A[mid])
lo = mid + 1;
else
hi = mid - 1;
}
return -1; //一定有峰值,所以永远不会执行这一句。
}
}
与LintCode不同在于,需要先判断第一个/最后一个元素是否为峰值。
class Solution {
public int findPeakElement(int[] nums) {
int len = nums.length;
if(len == 1 || nums[0] > nums[1]) return 0; //第一个元素是否是峰值
if(nums[len-1] > nums[len-2]) return len-1; //最后一个元素是否是峰值
int lo = 1, hi = nums.length-2;
while(lo <= hi) {
int mid = lo + (hi-lo)/2;
if(nums[mid] > nums[mid-1] && nums[mid] > nums[mid+1])
return mid;
if(nums[mid] > nums[mid-1]) lo = mid + 1;
else hi = mid - 1;
}
return -1;
}
}
五 temp总结
5.1 二分法:寻找满足条件的第一个元素
写法1:
while循环结束后,lo代表满足条件的第一个元素的位置。假设nums = [ 0,1,2,3,4 ],长度为5。此时,lo的取值有两种可能——
第一种情况,lo = 5,超出nums索引范围,代表nums中没有满足条件的元素。
第二种情况,lo取值在0~4之间,代表满足条件的第一个元素位置为lo。
int lo = 0, hi = nums.length-1;
while(lo <= hi) {
int mid = lo + (hi-lo) / 2;
if(nums[mid] 满足条件)
hi = mid - 1;
else
lo = mid + 1;
}
if(lo == nums.length) return -1; //没有满足条件的元素
return nums[lo]; //满足条件的第一个位置为lo
写法2:
int lo = 0, hi = nums.length - 1;
while(lo < hi) {
int mid = lo + (hi - lo) / 2;
if(nums[mid] 满足条件)
hi = mid;
else
lo = mid + 1;
}
return nums[lo]; //或者 nums[hi],因为此时lo = hi
5.2 二分法:寻找满足条件的最后一个元素
写法1:
while循环结束后,hi代表满足条件的最后一个元素的位置。假设nums = [ 0,1,2,3,4 ],长度为5。此时,hi的取值有两种可能——
第一种情况,hi = -1,超出nums索引范围,代表nums中没有满足条件的元素。
第二种情况,hi取值在0~4之间,代表满足条件的最后一个元素位置为hi。
int lo = 0, hi = nums.length-1;
while(lo <= hi) {
int mid = lo + (hi-lo)/2;
if(nums[mid]满足条件)
lo = mid + 1;
else
hi = mid - 1;
}
if(hi == 0) return -1;
return nums[hi];