- 基本实现;<=
- 1.求x的平方根;<=
- 2.寻找比目标字母大的最小字母;<=
- 3.有序数组的单一元素;<
- 4.查找元素在有序数组中的第一个位置和最后一个位置;<=
- 5.选转排序数组的最小值;<
- 6.搜索旋转排序数组;<=
- 7.搜索插入位置;
正常实现
代码:
[0,len-1] l<=h return -1;
public int binarySearch(int[] nums, int key) {
int l = 0, h = nums.length - 1;
while (l <= h) {
int m = l + (h - l) / 2;
if (nums[m] == key) {
return m;
} else if (nums[m] > key) {
h = m - 1;
} else {
l = m + 1;
}
}
return -1;
}
1. 求x的平方根
解法:二分查找
- 对1-x/2之间的值进行二分,left = 1, right = x/2; while(left <= right) 注意是<=!;
- 注意mid*mid 的值必须强制转换为long(防止溢出),然后进行比较;
- 缩小范围的临界点 right = mid-1, left = mid+1;
- 因为循环条件为left <= right,且返回整数值,所以最终返回right(left > right 终止循环,此时 left*left > 目标值,而right * right < 目标值,选小的数作为结果(向下取整)。
实现:
public int mySqrt(int x) {
if(x == 0) return 0;
if(x <= 3) return 1;
int left = 1;
int right = x/2;
while(left <= right){
int mid = left + (right - left)/2;
long temp = (long)mid * mid; //需要强制类型转换
if(temp == x) return mid;
else if(temp > x){
right = mid - 1;
}
else{
left = mid + 1;
}
}
return right;
}
2.寻找比目标字母大的最小字母
解法:二分查找
left = 0, right = len; left < right;
如果当前mid值 == target,left = mid + 1;
如果当前mid值 < target, left = mid + 1;
如果当前mid值 > target, right = mid;
返回left%len;(left = right 可能=[1,len])
实现:
public char nextGreatestLetter(char[] letters, char target) {
int len = letters.length;
int left = 0;
int right = len-1;
int ans = 0;
while(left <= right){
int mid = left + (right - left)/2;
if(letters[mid] <= target){
left = mid + 1;
}
else{
right = mid -1;
}
}
return letters[left%len];
}
3.有序数组中的单一元素
解法: 二分查找
left = 0, right = len-1; left < right(重点!)
判断mid == mid+1/ mid-1;不等于返回;
如果== mid+1: 通过两边的奇偶判断目标位于哪边;
== mid-1,判断两边长度的奇偶....
public int singleNonDuplicate(int[] nums) {
int left = 0;
int right = nums.length - 1;
while(left < right){ //重点
int mid = left + (right - left)/2;
if(nums[mid] != nums[mid - 1] && nums[mid] != nums[mid + 1]){
return nums[mid];
}
else if(nums[mid] == nums[mid - 1]){
if((mid - left - 1)%2 == 0){
left = mid + 1;
}
else right = mid - 2;
}
else{
if((mid - left)%2 == 0){
left = mid + 2;
}
else right = mid - 1;
}
}
System.out.println(left);
System.out.println(right);
return nums[left];
}
4.查找元素在数组中的第一个位置和最后一个位置
查找第一个位置:
- left = 0, right = len-1, left <= right;
- mid > target : right = mid-1;
- mid == target : right = mid-1; (因为循环结束条件是left>right,所以返回left时可保证不丢失此相等值)
- mid < target : left = mid+1。
- return:left < len 且 left == target 时返回left,否则返回-1。
private int firstPos(int[] nums,int target){
int left = 0;
int right = nums.length - 1;
while(left <= right){
int mid = (left + right)/2;
if(nums[mid] == target)
right = mid - 1; //重点
else if(nums[mid] < target)
left = mid + 1;
else if(nums[mid] > target)
right = mid - 1;
}
if(left < nums.length && nums[left] == target) return left;//重点
else return -1;
}
查找最后一个位置:
- left = 0, right = n, left <= right;
- mid < target : left = mid + 1;
- mid == target : left = mid + 1; (重点!如果mid是最后一个值则返回的是left-1来保证)
- mid > target : right = mid - 1;
- return: return (left - 1 >= 0 && (a[left - 1] == target))? left - 1: -1;
private int lastPos(int[] nums,int target){
int left = 0;
int right = nums.length - 1;
while(left <= right){
int mid = (left + right)/2;
if(nums[mid] == target)
left = mid + 1; //重点
else if(nums[mid] < target)
left = mid + 1;
else if(nums[mid] > target)
right = mid - 1;
}
if(left > 0 && nums[left-1] == target) return left - 1; //重点
else return -1;
}
5. 旋转排序数组的最小值
- left = 0, right = len - 1, legt < right(重点!!)
- 前提: nums[left] < right 则返回left;
- mid > left: left = mid + 1;
- mid < right: right = mid;
- else: left++(left == mid == right情况)
- return: nums[left]
代码:
public int findMin(int[] nums) {
int left = 0;
int right = nums.length - 1;
while(left < right){ //重点!!!
int mid = left + (right - left)/2;
if(nums[left] < nums[right]){
return nums[left];
}
else if(nums[mid] > nums[left]){
left = mid + 1;
}
else if(nums[mid] < nums[right]){
right = mid;
}
else{
left++;
}
}
return nums[left];
}
6.搜索旋转排序数组
- left = 0, right = len-1, left <= right;
- mid == target, return;
- left < mid && 1)[left,<= target,< mid]: right = mid - 1; 2) [mid, < target <= right] left = mid + 1;
- mid < right && 1)[mid,< target,<= right]: left = mid + 1; 2)[left,<= target,< mid] rigth = mid - 1。
- (不可能有 = mid情况因为 mid == target已经判断,所以mid一定不是)
public int search(int[] nums, int target) {
if (nums.length == 0 || nums == null) return -1;
int length = nums.length;
int start = 0;
int end = length - 1;
while (start <= end) {
int mid = start + (end - start) / 2;
if (nums[mid] == target) return mid;
else {
if (nums[mid] >= nums[start]) {
if (nums[start] <= target && target < nums[mid]) {
end = mid - 1;
} else start = mid + 1;
} else {
if (nums[mid] < target && target <= nums[end]) {
start = mid + 1;
} else end = mid - 1;
}
}
}
return -1;
}