欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 健康 > 养生 > Day01--二分查找

Day01--二分查找

2024/10/25 4:21:43 来源:https://blog.csdn.net/qq_45655136/article/details/142285034  浏览:    关键词:Day01--二分查找
  1. 代码随想录https://www.programmercarl.com/0704.%E4%BA%8C%E5%88%86%E6%9F%A5%E6%89%BE.html#%E6%80%BB%E7%BB%93
  2. 剑指offer题解:https://offer.hi-dhl.com/#/algorithm/03-number
  3. 《剑指offer>>全解https://fantianzuo.blog.csdn.net/article/details/107591709
  4. https://github.com/doocs/leetcode/tree/main

本项目包含 LeetCode、《剑指 Offer(第 2 版)》、《剑指 Offer(专项突击版)》、《程序员面试金典(第 6 版)》等题目的相关题解。

  1. https://www.xiehai.zone/JavaLeetCode/lcof1/03.html

二分查找

https://www.programmercarl.com/0704.%E4%BA%8C%E5%88%86%E6%9F%A5%E6%89%BE.html#%E6%80%BB%E7%BB%93

704. 二分查找

力扣:https://leetcode.cn/problems/binary-search/

  1. 左闭右开
class Solution {public int search(int[] nums, int target) {int left=0,right=nums.length;while(left<right){int mid=left+((right-left)>>1);if(nums[mid]==target){return mid;}else if(nums[mid]<target){left=mid+1;}else{right=mid;}}return -1;}
}

2.左闭右闭

class Solution {public int search(int[] nums, int target) {// 避免当 target 小于nums[0] nums[nums.length - 1]时多次循环运算if (target < nums[0] || target > nums[nums.length - 1]) {return -1;}int left = 0, right = nums.length - 1;while (left <= right) {int mid = left + ((right - left) >> 1);if (nums[mid] == target) {return mid;}else if (nums[mid] < target) {left = mid + 1;}else { // nums[mid] > targetright = mid - 1;}}// 未找到目标值return -1;}
}

在计算中间索引时,如果 leftright 是很大的整数(特别是在极端情况下,它们的和超过了整数类型的上限),直接使用 (left + right) / 2 可能会导致溢出。这是因为 left + right 可能会超出所能表示的最大值,从而导致结果不正确。

为了解决这个问题,可以使用以下公式来计算中间索引,以避免溢出:

mid = left + (right - left) / 2

这种写法首先减去 left 从而避免了直接相加,确保不会发生溢出。这样可以安全地计算中间索引。

35. 搜索插入位置simple

力扣:https://leetcode.cn/problems/search-insert-position/description/
解题思路:

  • 1目标值在数组所有元素之前
  • 2目标值等于数组中某一个元素
  • 3目标值插入数组中的位置
  • 4目标值在数组所有元素之后
  1. 左闭右闭
class Solution {public int searchInsert(int[] nums, int target) {int left=0,right=nums.length-1;while(left<=right){//直接用>>位运算符比/运算符要快int mid=left+((right-left)>>1);if(nums[mid]==target){return mid;}else if(nums[mid]<target){left=mid+1;}else right=mid-1;}return right+1;//134}
}
  1. 左闭右开
class Solution {public int searchInsert(int[] nums, int target) {int left=0,right=nums.length;while(left<right){//直接用>>位运算符比/运算符要快int mid=left+((right-left)>>1);if(nums[mid]==target){return mid;}else if(nums[mid]<target){left=mid+1;}else right=mid;}return right;//134}
}

34.在排序数组中查找元素的第一个和最后一个位置medium

力扣:https://leetcode.cn/problems/find-first-and-last-position-of-element-in-sorted-array/description/
解题思路:
共有三种情况:

  • 情况一:target 在数组范围的右边或者左边,例如数组{3, 4, 5},target为2或者数组{3, 4, 5},target为6,此时应该返回{-1, -1}
  • 情况二:target 在数组范围中,且数组中不存在target,例如数组{3,6,7},target为5,此时应该返回{-1, -1}
  • 情况三:target 在数组范围中,且数组中存在target,例如数组{3,6,7},target为6,此时应该返回{1, 1}
    分别寻找左区间和右区间,左右根据左右区间做最后判断
    比较好的题解链接:https://leetcode.cn/problems/find-first-and-last-position-of-element-in-sorted-array/solutions/536360/yi-wen-dai-ni-gao-ding-er-fen-cha-zhao-j-ymwl/
  1. 左闭右闭
class Solution {public int[] searchRange(int[] nums, int target) {int leftBorder=getLeftBorder(nums,target);int rightBorder=getRightBorder(nums,target);// 情况一:target在数组范围的右边或者左边if (leftBorder == -2 || rightBorder == -2) return new int[]{-1, -1};// 情况三:target 在数组范围中,且数组中存在targetif (rightBorder - leftBorder > 1) return new int[]{leftBorder + 1, rightBorder - 1};// 情况二:target 在数组范围中,且数组中不存在targetreturn new int[]{-1, -1};}int getRightBorder(int[] nums, int target) {int left = 0;int right = nums.length - 1;int rightBorder = -2; // 记录一下rightBorder没有被赋值的情况while (left <= right) {int middle = left + ((right - left) / 2);if (nums[middle] > target) {right = middle - 1;} else { // 寻找右边界,nums[middle] == target的时候更新leftleft = middle + 1;rightBorder = left;}}return rightBorder;}int getLeftBorder(int[] nums, int target) {int left = 0;int right = nums.length - 1;int leftBorder = -2; // 记录一下leftBorder没有被赋值的情况while (left <= right) {int middle = left + ((right - left) / 2);if (nums[middle] >= target) { // 寻找左边界,nums[middle] == target的时候更新rightright = middle - 1;leftBorder = right;} else {left = middle + 1;}}return leftBorder;}
}
class Solution {public int[] searchRange (int[] nums, int target) {int upper = upperBound(nums,target);int low = lowerBound(nums,target);  //不存在情况if (upper < low) {return new int[]{-1,-1};}return new int[]{low,upper};}//计算下边界int lowerBound(int[] nums, int target) {int left = 0, right = nums.length - 1;while (left <= right) {//这里需要注意,计算midint mid = left + ((right - left) >> 1);if (target <= nums[mid]) {//当目标值小于等于nums[mid]时,继续在左区间检索,找到第一个数right = mid - 1;}else if (target > nums[mid]) {//目标值大于nums[mid]时,则在右区间继续检索,找到第一个等于目标值的数left = mid + 1;}}return left;}//计算上边界int upperBound(int[] nums, int target) {int left = 0, right = nums.length - 1;while (left <= right) {          int mid = left + ((right - left) >> 1);if (target >= nums[mid]) {left = mid + 1;               }else if (target < nums[mid]) {right = mid - 1;}            }return right;}
}

69. x的平方根medium

class Solution {public int mySqrt(int x) {if(x==0) return 0;int left=1,right=x;while(left<=right){int mid=left+(right-left)/2;if(mid==x/mid)return mid;else if(mid<x/mid) left=mid+1;else {right=mid-1;}}return left-1;}
}

367. 有效的完全平方数simple

class Solution {public boolean isPerfectSquare(int num) {int left=1,right=num;while(left<=right){int mid=left+(right-left)/2;if(mid*mid==num)return true;else if(mid<num/mid) left=mid+1;else {right=mid-1;}}return false;}
}

复杂度分析

时间复杂度:O(logn),其中 n 为正整数 num 的最大值。

空间复杂度:O(1)。

33.搜索旋转排序数组medium

力扣:https://leetcode.cn/problemset/
参考:https://leetcode.cn/problems/find-first-and-last-position-of-element-in-sorted-array/solutions/536360/yi-wen-dai-ni-gao-ding-er-fen-cha-zhao-j-ymwl/

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)>>1);if(nums[mid]==target){return mid;}//落在同一数组的情况,同时落在数组1或数组2if(nums[mid]>=nums[left]){//target落在left和mid之间,则移动我们的right,完全有序的一个区间内查找if(nums[mid]>target&&target>=nums[left]){right=mid-1;//target落在right和Mid之间,有可能在数组1,也有可能在数组2}else if(target>nums[mid]||target<nums[left]){left=mid+1;}}//不落在同一数组的情况,left在数组1,mid落在数组2else if(nums[mid]<nums[left]){//有序的一段区间,target 在 mid 和 right 之间if (nums[mid] < target && target <= nums[right]) {left = mid + 1;// 两种情况,target 在left 和 mid 之间} else if (target < nums[mid] || target > nums[right]) {right = mid - 1;}}}return -1;}}

154.寻找旋转排序数组中的最小值II(困难)

class Solution {public int findMin(int[] nums) {int left=0;int right=nums.length-1;while(left<right){//单调递增时直接返回if(nums[left]<nums[right]){return nums[left];}int mid=left+(right-left)/2;if(nums[right]<nums[mid]){left=mid+1;}else if(nums[right]>nums[mid]) {right=mid;}else{right--;}}return nums[left];}
}

81. 搜索旋转排序数组II(medium)

力扣:https://leetcode.cn/problems/search-in-rotated-sorted-array-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)>>1);if(nums[mid]==target){return true;}if(nums[mid]==nums[left]){left++;continue;}//落在同一数组的情况,同时落在数组1或数组2if(nums[mid]>=nums[left]){//target落在left和mid之间,则移动我们的right,完全有序的一个区间内查找if(nums[mid]>target&&target>=nums[left]){right=mid-1;//target落在right和Mid之间,有可能在数组1,也有可能在数组2}else if(target>nums[mid]||target<nums[left]){left=mid+1;}}//不落在同一数组的情况,left在数组1,mid落在数组2else if(nums[mid]<nums[left]){//有序的一段区间,target 在 mid 和 right 之间if (nums[mid] < target && target <= nums[right]) {left = mid + 1;// 两种情况,target 在left 和 mid 之间} else if (target < nums[mid] || target > nums[right]) {right = mid - 1;}}}return false;}
}

153.寻找旋转数组中的最小值(medium)

力扣:
解题思路:

  • 数组完全有序nums[left]<nums[right],返回nums[left]
  • left和Mid都在前半部分,单调递增区间,left=mid+1
  • left在前半部分,mid在后半部分,right=mid
class Solution {public int findMin(int[] nums) {int left=0;int right=nums.length-1;while(left<=right){//单调递增时直接返回if(nums[left]<=nums[right]){return nums[left];}int mid=left+(right-left)/2;if(nums[left]<=nums[mid]){left=mid+1;}else {right=mid;}}return -1;}
}

74. 搜索二维矩阵medium

力扣:https://leetcode.cn/problems/search-a-2d-matrix/description/

class Solution {public boolean searchMatrix(int[][] matrix, int target) {int left=0;int n=matrix[0].length;int m=matrix.length;int right=m*n-1;while(left<=right){int mid=left+(right-left)/2;int nums=matrix[mid/n][mid%n];if(nums==target){return true;}else if(nums<target){left=mid+1;}else{right=mid-1;}}return false;}
}

441.排列硬币(simple)

class Solution {public int arrangeCoins(int n) {int left = 1, right = n;while (left < right) {int mid = (right - left + 1) / 2 + left;if ((long) mid * (mid + 1) <= (long) 2 * n) {left = mid;} else {right = mid - 1;}}return left;
}
}

162.寻找峰值(medium)

参考链接:hhttps://leetcode.cn/problems/find-peak-element/solutions/6695/hua-jie-suan-fa-162-xun-zhao-feng-zhi-by-guanpengc

class Solution {public int findPeakElement(int[] nums) {int n=nums.length;if(n==1){return 0;}int left=0;int right=n-1;while(left<right){int mid=left+(right-left)/2;if(nums[mid]<nums[mid+1]){left=mid+1;}else right=mid;}return right;}
}

4.寻找两个正序(困难)

解题思路:参考链接https://blog.lichangao.com/daily_practice/leetcode/array/other.html#_0004-%E5%AF%BB%E6%89%BE%E4%B8%A4%E4%B8%AA%E6%AD%A3%E5%BA%8F%E6%95%B0%E7%BB%84%E7%9A%84%E4%B8%AD%E4%BD%8D%E6%95%B0
给定两个数组A、B,如何找到从小到大排列的第K个数?
只要让k取值(n+m)/2,就可以得到中位数。令k1=k/2,k2=k-k/2,则:

  • 当A[k1]<B[k2]时,去掉A[<=k1]的元素
  • 当A[k1]>B[k2]时,去掉B[<=k2]的元素
  • 当A[k1]=B[k2]时,去掉A[<=k1]或B[<=k2]的元素
    综上,可以将其转化为一个递归的问题,每次k的规模都减少一半,而k取值(n+m)/2
class Solution {public int find(int[] nums1,int i,int[] nums2,int j,int k){// 保证 nums1 的元素更少,方便处理if (nums1.length - i > nums2.length - j) return find(nums2, j, nums1, i, k);// nums1 为空,直接取 nums2 的第 k 个元素if (nums1.length == i) return nums2[j + k - 1];// k = 1 时,取两数组第一个元素的最小值if (k == 1) return Math.min(nums1[i], nums2[j]);// 分别对应两数组 k / 2 的下一个位置int si = Math.min((int)nums1.length, i + k / 2);int sj = j + k - k / 2;if (nums1[si - 1] < nums2[sj - 1]) {return find(nums1, si, nums2, j, k - (si - i));} else {return find(nums1, i, nums2, sj, k - (sj - j));}}public double findMedianSortedArrays(int[] nums1, int[] nums2) {int n=nums1.length+nums2.length;if(n%2==0){int left=find(nums1,0,nums2,0,n/2);int right=find(nums1,0,nums2,0,n/2+1);return (left+right)/2.0;}else{return find(nums1,0,nums2,0,n/2+1);}}}

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com