二分法难点:数据索引的更新
/* The isBadVersion API is defined in the parent class VersionControl.
boolean isBadVersion(int version); */
public class Solution extends VersionControl {
public int firstBadVersion(int n) {
/*如果第m个错误的版本出现错误,那么第一个出现错误的版本[l.m]之间 h=m;
如果第m个错误的版本不是错误,那么第一个出现错误的版本[m+1.h]之间 l=m+1;
由于h=m;所以循环条件l<h;否则会出先死循环现象
*/
int l=1;
int h=n;
while(l<=h){
int m=l+(h-l)/2;
if(isBadVersion(m)==true){
h=m-1;
}else{
l=m+1;
}
}
return l;
}
}
查找只出现一次的那个元素
class Solution {
public int singleNonDuplicate(int[] nums) {
/*考虑用二分法思想
设单个元素出现的索引为index;设m为偶数,在m+1<index时候,nums[m]==nums[m+1];
在m+1>index时候,nums[m]!=nums[m+1]
依据这个原则来进行索引的更新
*/
int l=0;
int h=nums.length-1;
while(l<h){
int m=l+(h-l)/2;
if(m%2==1){
m--;
}//保证是偶数索引,访问到的区间都是奇数区间
if(nums[m]==nums[m+1]){
//索引index在后半段[m+2,h]
l=m+2;
}else{
//索引在前半段[l,m]
h=m;
}
}
return nums[l];
}
}
查找给定目标元素第一次和最后一次出现的位置
class Solution {
public int[] searchRange(int[] nums, int target) {
int firstIndex= searchFirstIndex(nums, target);
int lastIndex =searchFirstIndex( nums, target+1)-1;
//1.索引都是有效值,不为空,
if(firstIndex==nums.length||nums[firstIndex]!=target){
return new int[]{-1,-1};
}else {
return new int[] {firstIndex,Math.max(firstIndex,lastIndex)};
}
}
private int searchFirstIndex(int[] nums, int target){
int l=0;
int h=nums.length;
while(l<h){
int m=l+(h-l)/2;
if(nums[m]>=target){
h=m;
}else{
l=m+1;
}
}
return l;
}
}
旋转数组中的最小元素
class Solution {
public int findMin(int[] nums) {
/*1.利用二分查找*/
int l=0;
int h=nums.length-1;
while(l<h){
int m=l+(h-l)/2;
//如果中间元素大于第一个l,小于后一个元素,那么最小的元素一定在后半段区间
if(nums[m]<=nums[h]){
h=m;
}else{
l=m+1;
}
}
return nums[l];
}
}
class Solution {
public int[] searchRange(int[] nums, int target) {
int[] result = new int[2];
result[0]= searchFirstIndex(nums, target);
result[2]=searchLastIndex(nums, target);
return result;
}
private int searchFirstIndex(int[] nums, int target){
int firstIndex=-1;
int l=0;
int h=nums.length-1;
while(l<h){
int m=l+(h-l)/2;
if(nums[m]>=target){
h=m;
}else{
l=m+1;
}
}
if(nums[l]==target) firstIndex=l;
return firstIndex;
}
//最后一次出现的位置
private int searchLastIndex(int[] nums, int target){
int lastIndex=-1;
int l=0;
int h=nums.length-1;
while(l<h){
int m=l+(h-l)/2;
if(nums[m]<=target){
l=m;
}else{
h=m-1;
}
}
if(nums[l]==target) lastIndex=l;
return lastIndex;
}
}
class Solution {
public int[] searchRange(int[] nums, int target) {
int[] result = {-1,-1};
result[0]= searchFirstIndex(nums, target);
//如果查找到了一个索引,在继续查找是否有其他的索引
if(result[0]!=-1){
result[1]=searchLastIndex(nums, result[0],target);
}
return result;
}
//第一次出现的位置
private int searchFirstIndex(int[] nums, int target){
int firstIndex=-1;
int l=0;
int h=nums.length-1;
while(l<=h){
int m=l+(h-l)/2;
if(nums[m]>target){
h=m-1;
}else if(nums[m]<target){
l=m+1;
}else{
firstIndex=m;
h=m-1;
}
}
return firstIndex;
}
//最后一次出现的位置
private int searchLastIndex(int[] nums, int left,int target){
int lastIndex=-1;
int l=left;
int h=nums.length-1;
while(l<=h){
int m=l+(h-l)/2;
if(nums[m]>target){
h=m-1;
}else if(nums[m]<target){
l=m+1;
}else{
lastIndex=m;
l=m+1;
}
}
return lastIndex;
}
}