Binary lookup is usually used in an ordered array.
Square root of x
Implement the int sqrt(int x) function.
Calculates and returns the square root of X, where x is a nonnegative integer.
Since the return type is an integer, only the integer part of the result will be retained, and the decimal part will be rounded off.
Example 1:
Input: 4
Output: 2
Example 2:
Input: 8
Output: 2
Note: the square root of 8 is 2.82842,
Since the return type is an integer, the decimal part will be rounded off.
Source: LeetCode
Link: https://leetcode-cn.com/problems/sqrtx
When sqrt() method is not used, we can traverse [1,n - 1] to get the final result, but it takes time. Therefore, we need to use binary search. The numbers of [1,n - 1] are ordered and can be realized through binary search.
Basic idea:
1. Binary search in [1,x]
- The initial value is left = 1,right = x, and the intermediate variables are defined as mid and sqrt (based on the following mid method, the initial value of right needs to be x)
- When left < = right, cycle continuously, and mid = left + (right - left) / 2
- Get sqrt, i.e. sqrt = x / mid, and then update left and right according to the size of sqrt and mid:
① sqrt == mid, indicating that the square of sqrt is just equal to x, and sqrt is returned directly
② Sqrt > mid indicates that the mid is too small, so in order to make sqrt and mid equal, we need to increase the mid, so we need to move left so that left = mid + 1
③ Sqrt < mid indicates that the mid is too large, so in order to make sqrt and mid equal, you need to reduce the mid, so you need to reduce right so that right = mid - 1
2. When left > right, return right directly to ensure rounding down. That is, for example, when 8 exits the loop, left is 3 and right is 2, because the square root of 8 is 2.82842... And rounding down is 2, that is, right At the same time, if x is equal to 0, it can just return 0
Why mid = left + (right - left) / 2
We need to take the middle value of [left,right] (the tolerance of this interval is 1, so each number differs by 1). Then (right - left) means that there are a total of right - left numbers in this interval, divided by half, and plus left is the middle number of [left,right] interval.
Corresponding code:
class Solution { public int mySqrt(int x) { int l = 1,r = x,mid,sqrt; while(l <= r){ mid = l + (r - l) / 2; sqrt = x / mid; if(sqrt == mid) return sqrt; else if(mid > sqrt) r = mid - 1; else l = mid + 1; } return r; } }
Operation results:
Finds the first and last positions of elements in a sorted array
Given an integer array nums arranged in ascending order and a target value target. Find the start and end positions of the given target value in the array.
If the target value target does not exist in the array, return [- 1, - 1].
Advanced:
Can you design and implement an algorithm with time complexity of O(log n) to solve this problem?
Example 1:
Input: num = [5,7,7,8,8,10], target = 8
Output: [3,4]
Example 2:
Input: num = [5,7,7,8,8,10], target = 6
Output: [- 1, - 1]
Example 3:
Input: num = [], target = 0
Output: [- 1, - 1]
Tips:
0 <= nums.length <= 105
-109 <= nums[i] <= 109
nums is a non decreasing group
-109 <= target <= 109
Source: LeetCode
Link: https://leetcode-cn.com/problems/find-first-and-last-position-of-element-in-sorted-array
Use twice binary search to find the left and right boundaries of target. At the same time, before the second binary search, you can use the first binary search to determine whether the target exists in the array. If it does not exist, it returns [- 1, - 1]. Otherwise, you can use the second binary search.
Corresponding code:
class Solution { public int[] searchRange(int[] nums, int target) { int right = upperBound(nums,0,nums.length - 1,target); /* If right is equal to - 1, it means that the target does not exist in the array or the array length is 0. It is returned directly [-1,-1],There is no need for a second binary search */ if(right == -1) return new int[]{-1,-1}; int left = lowerBound(nums,0,right,target); return new int[]{left,right}; } //Find right boundary public int upperBound(int[] nums,int low,int high,int target){ int mid; while(low <= high){ mid = (low + high) / 2; if(nums[mid] <= target)//Solve the right boundary, so you need to keep moving to the right low++; else high = mid - 1; } /* If high is in a reasonable range (i.e. greater than or equal to 0, the length of the array is not 0) If num [high] = = target, it indicates that the target exists in the array, so it returns high,Otherwise, - 1 is returned, indicating that the length of the array is 0 or the target is not in the array */ return high >= 0 && nums[high] == target ? high : -1; } //Find left boundary public int lowerBound(int[] nums,int low,int high,int target){ int mid; while(low <= high){ mid = (low + high) / 2; if(nums[mid] >= target)//Keep moving to the left to get the left boundary high = mid - 1; else low = mid + 1; } return low; } }
Operation results: