题目
打算先跟着代码随想录刷题,最后补补hot100,剑指offer,每天最少两题,最后可能合计200多道题吧,应该够用了。 704.二分查找 解法总结:1.反应出使用二分查找,有序,无重复元素,碰到这个情况要想到使用二分 ;2.记住条件 left<=right 时间复杂度O(logn),最好O(1),最坏O(logn)
代码
var search = function ( nums, target ) {
let left = 0 ;
let mid = 0 ;
let right = nums. length- 1 ;
while ( left <= right) {
mid = parseInt ( left + right) ;
if ( nums[ mid] === target) {
return mid;
} else if ( nums[ mid] > target) {
right= mid- 1 ;
} else if ( nums[ mid] < target) {
left= mid+ 1 ;
}
}
return - 1 ;
} ;
一些自己的分析
时间复杂度O(logn),最好O(1),最坏O(logn) 复习了parseInt,学到了相加防大数的位运算操作和(right - left) / 2 + left; 二分法前提:有序,无重复元素,碰到这个情况要想到使用二分 边界问题,第一次提交没考虑left = right的情况 看了下分析,两种定义情况
如果target 是在一个在左闭右闭的区间里,也就是[left, right] ,那么while (left <= right) 要使用 <= , if (nums[middle] > target) right 要赋值为 middle - 1 如果target 是在一个在左闭右开的区间里,也就是[left, right) ,那么while (left < right) 要使用 < , if (nums[middle] > target) right 要赋值为 middle
其他相关题型
var searchInsert = function ( nums, target ) {
let left = 0 ;
let mid = 0 ;
let right = nums. length- 1 ;
while ( left <= right) {
mid = left + ( ( right - left) >> 1 ) ;
if ( nums[ mid] === target) {
return mid;
} else if ( nums[ mid] > target) {
right= mid- 1 ;
} else if ( nums[ mid] < target) {
left= mid+ 1 ;
}
}
return left
} ;
我自己的想法,先找到一个目标值,再以目标值为起点向两边逐个遍历 虽然过了,但最后分析了下,O(n)了,看了下答案,要用二分法分别找左右边界
var searchRange = function ( nums, target ) {
let left = 0 ;
let mid = 0 ;
let right = nums. length- 1 ;
let targetStart= - 1 ;
let targetEnd= - 1 ;
while ( left <= right) {
mid = left + ( ( right - left) >> 1 ) ;
if ( nums[ mid] === target) {
targetStart = mid;
targetEnd = mid;
for ( ; targetEnd < nums. length; targetEnd++ ) {
if ( nums[ targetEnd] !== target) {
targetEnd-- ;
break ;
}
}
for ( ; targetStart > - 1 ; targetStart-- ) {
if ( nums[ targetStart] !== target) {
targetStart++ ;
break ;
}
}
if ( targetEnd === nums. length) targetEnd= nums. length- 1 ;
if ( targetStart === - 1 ) targetStart= 0 ;
break ;
} else if ( nums[ mid] > target) {
right= mid- 1 ;
} else if ( nums[ mid] < target) {
left= mid+ 1 ;
}
}
return [ targetStart, targetEnd] ;
} ;
const searchBorder = ( nums, target, startOrEnd ) => {
let left = 0 ;
let mid = 0 ;
let right = nums. length- 1 ;
let result = - 2 ;
while ( left <= right) {
mid = left + ( ( right - left) >> 1 ) ;
if ( nums[ mid] === target) {
if ( startOrEnd === 'start' ) {
right = mid- 1 ;
result = mid;
} else {
left = mid+ 1 ;
result = mid;
}
} else if ( nums[ mid] > target) {
right = mid- 1 ;
} else {
left = mid+ 1 ;
}
}
if ( result!== - 2 ) {
return result;
} else {
return - 1 ;
}
} ;
var searchRange = function ( nums, target ) {
let targetStart = searchBorder ( nums, target, 'start' ) ;
let targetEnd = searchBorder ( nums, target, 'end' ) ;
return [ targetStart, targetEnd] ;
} ;
二分查找一次过 看了官方解析,回想起了被牛顿迭代支配的恐惧
var mySqrt = function ( x ) {
let left = 0
let right = x
let mid
while ( left <= right) {
mid = parseInt ( left + ( right - left) / 2 )
if ( mid * mid === x) {
return mid
} else if ( mid * mid > x) {
right = mid - 1
} else {
left = mid + 1
}
}
if ( mid * mid > x) {
return mid- 1
} else {
return mid
}
} ;
var mySqrt = function ( x ) {
if ( x === 0 ) {
return 0
}
let C = x
let x0 = x
let xi
while ( true ) {
xi = 0.5 * ( x0 + C / x0)
if ( Math. abs ( x0 - xi ) < 1e-7 ) {
break
}
x0 = xi
}
return parseInt ( x0)
} ;
和上题代码基本相同,判断下true和false即可 官方使用牛顿法,在取整之后再迭代似乎有点问题,x0-xi加上绝对值之后会陷入死循环。