文章目錄
二分查找框架
int binarySearch(int[] nums, int target) {
int left = 0, right = ...;
while(...) {
int mid = left + (right - left) / 2;
if (nums[mid] == target) {
...
} else if (nums[mid] < target) {
left = ...
} else if (nums[mid] > target) {
right = ...
}
}
return ...;
}
分析二分查找的一個技巧是:不要出現 else,而是把所有情況用 else if 寫清楚,這樣可以清楚地展現所有細節
計算 mid 時需要防止溢出,代碼中 left + (right - left) / 2 就和 (left + right) / 2 的結果相同,但是有效防止了 left 和 right 太大直接相加導致溢出。
int binary_search(int[] nums, int target) {
int left = 0, right = nums.length - 1;
while(left <= right) {
int mid = left + (right - left) / 2;
if (nums[mid] < target) {
left = mid + 1;
} else if (nums[mid] > target) {
right = mid - 1;
} else if(nums[mid] == target) {
// 直接返回
return mid;
}
}
// 直接返回
return -1;
}
int left_bound(int[] nums, int target) {
int left = 0, right = nums.length - 1;
while (left <= right) {
int mid = left + (right - left) / 2;
if (nums[mid] < target) {
left = mid + 1;
} else if (nums[mid] > target) {
right = mid - 1;
} else if (nums[mid] == target) {
// 別返回,鎖定左側邊界
right = mid - 1;
}
}
// 最後要檢查 left 越界的情況
if (left >= nums.length || nums[left] != target)
return -1;
return left;
}
int right_bound(int[] nums, int target) {
int left = 0, right = nums.length - 1;
while (left <= right) {
int mid = left + (right - left) / 2;
if (nums[mid] < target) {
left = mid + 1;
} else if (nums[mid] > target) {
right = mid - 1;
} else if (nums[mid] == target) {
// 別返回,鎖定右側邊界
left = mid + 1;
}
}
// 最後要檢查 right 越界的情況
if (right < 0 || nums[right] != target)
return -1;
return right;
}
704. 二分查找
class Solution {
public int search(int[] nums, int target) {
int left = 0;
int right = nums.length-1;
while(left<=right){
int mid = left + (right-left)/2;
if(nums[mid]<target){
left = mid + 1;
}else if(nums[mid]>target){
right = mid - 1;
}else if(nums[mid]==target){
return mid;
}
}
return -1;
}
}
33. 搜索旋轉排序數組
class Solution {
public int search(int[] nums, int target) {
int left = 0;
int right = nums.length-1;
while(left<=right){
int mid = left+(right-left)/2;
if(nums[mid]==target){
return mid;
}
if(nums[mid]>=nums[left]){
if(nums[mid]>=target&&nums[left]<=target){
right = mid - 1;
}else{
left = mid + 1;
}
}else{
if(nums[right]>=target&&nums[mid]<=target){
left = mid + 1;
}else{
right = mid - 1;
}
}
}
return -1;
}
}
81. 搜索旋轉排序數組 II
class Solution {
public boolean search(int[] nums, int target) {
int left = 0;
int right = nums.length - 1;
while(left<=right){
int mid = left + (right-left)/2;
if(nums[mid]==target){
return true;
}
if(nums[mid]>nums[left]){
if(nums[mid]>=target&&nums[left]<=target){
right = mid -1;
}else{
left = mid + 1;
}
}else if(nums[mid]<nums[left]){
if(nums[mid]<=target&&nums[right]>=target){
left = mid + 1;
}else{
right = mid - 1;
}
}else{
left++;
}
}
return false;
}
}
153. 尋找旋轉排序數組中的最小值
class Solution {
public int findMin(int[] nums) {
int left = 0;
int right = nums.length - 1;
while(left<=right){
int mid = left + (right-left)/2;
if(nums[mid]>nums[right]){
left = mid + 1;
}else if(nums[mid]<nums[right]){
right = mid;
}else{
right = mid - 1;
}
}
return nums[left];
}
}
154. 尋找旋轉排序數組中的最小值 II
class Solution {
public int findMin(int[] nums) {
int left = 0;
int right = nums.length - 1;
while(left<=right){
int mid = left + (right-left)/2;
if(nums[mid]>nums[right]){
left = mid + 1;
}else if(nums[mid]<nums[right]){
right = mid;
}else{
right--;
}
}
return nums[left];
}
}
300. 最長上升子序列
class Solution {
public int lengthOfLIS(int[] nums) {
int[] tails = new int[nums.length];
int res = 0;
for(int num : nums) {
int left = 0, right = res;
while(left < right) {
int mid = (left + right) / 2;
if(tails[mid] < num) left = mid + 1;
else right = mid;
}
tails[left] = num;
if(res == right) res++;
}
return res;
}
}
275. H指數 II
class Solution {
public int hIndex(int[] citations) {
int len = citations.length;
if(len==0||citations[len-1]==0){
return 0;
}
int left = 0;
int right = len-1;
while(left<right){
int mid = left + (right-left)/2;
//區間 [mid, len - 1] 的長度,即 len - 1 - mid + 1 = len - mid
if(citations[mid]<len - mid){
left = mid + 1;
}else{
right = mid;
}
}
return len-left;
}
}
34. 在排序數組中查找元素的第一個和最後一個位置
class Solution {
public int[] searchRange(int[] nums, int target) {
int left = 0;
int right = nums.length - 1;
int FirstPosition = findFirstPosition(nums,target);
if(FirstPosition==-1){
return new int[]{-1,-1};
}
int LastPosition = findLastPosition(nums,target);
return new int[]{FirstPosition,LastPosition};
}
private int findFirstPosition(int[] nums,int target){
int left = 0;
int right = nums.length - 1;
while(left<=right){
int mid = left + (right-left)/2;
//尋找開始位置
if(nums[mid]>target){
right = mid - 1;
}else if(nums[mid]<target){
left = mid + 1;
}else if(nums[mid]==target){
right = mid - 1;
}
}
// 最後要檢查 left 越界的情況
if (left >= nums.length || nums[left] != target)
return -1;
return left;
}
private int findLastPosition(int[] nums, int target) {
int left = 0, right = nums.length - 1;
while (left <= right) {
int mid = left + (right - left) / 2;
if (nums[mid] < target) {
left = mid + 1;
} else if (nums[mid] > target) {
right = mid - 1;
} else if (nums[mid] == target) {
// 別返回,鎖定右側邊界
left = mid + 1;
}
}
// 最後要檢查 right 越界的情況
if (right < 0 || nums[right] != target)
return -1;
return right;
}
}
1095. 山脈數組中查找目標值
class Solution {
public int findInMountainArray(int target, MountainArray mountainArr) {
int size = mountainArr.length();
int Mountaintop = findMountaintop(mountainArr,0,size-1);
int res = findFromSortedArr(mountainArr,target,0,Mountaintop);
if(res!=-1){
return res;
}
res = findFromInversedArr(mountainArr,target,Mountaintop+1,size-1);
return res;
}
private int findMountaintop(MountainArray mountainArr,int l,int r){
while(l<r){
int mid = l + (r - l)/2;
if(mountainArr.get(mid)<mountainArr.get(mid+1)){
l = mid+1;
}else{
r = mid;
}
}
return l;
}
private int findFromSortedArr(MountainArray mountainArr,int target,int l,int r){
while(l<r){
int mid = l + (r-l)/2;
if(target==mountainArr.get(mid)){
return mid;
}else if(mountainArr.get(mid)<target){
l = mid + 1;
}else{
r = mid;
}
}
if (mountainArr.get(l) == target) {
return l;
}
return -1;
}
private int findFromInversedArr(MountainArray mountainArr,int target,int l,int r){
while(l<r){
int mid = l + (r-l)/2;
if(target==mountainArr.get(mid)){
return mid;
}else if(mountainArr.get(mid)>target){
l = mid + 1;
}else{
r = mid;
}
}
if (mountainArr.get(l) == target) {
return l;
}
return -1;
}
}
4. 尋找兩個有序數組的中位數
69. x 的平方根
class Solution {
public int mySqrt(int x) {
long left = 0;
// # 爲了照顧到 1 把右邊界設置爲 x // 2 + 1
long right = x / 2 + 1;
while (left < right) {
// 注意:這裏一定取右中位數,如果取左中位數,代碼會進入死循環
long mid = left + (right - left + 1) / 2;
if (mid * mid > x) {
right = mid - 1;
} else {
left = mid;
}
}
return (int) left;
}
}
374. 猜數字大小
class Solution extends GuessGame {
public int guessNumber(int n) {
int low = 1;
int high = n;
while (low <= high) {
int mid = low + (high - low) / 2;
int res = guess(mid);
if (res == 0)
return mid;
else if (res < 0)
high = mid - 1;
else
low = mid + 1;
}
return -1;
}
}
你知道的越多,你不知道的越多。
有道無術,術尚可求,有術無道,止於術。
如有其它問題,歡迎大家留言,我們一起討論,一起學習,一起進步