二分查找代码
class Solution {
public int searchInsert(int[] nums, int target) {
int left = 0, right = nums.length-1;
//注意循环条件
while (left <= right) {
//求mid
int mid = left + ((right - left ) >> 1);
//查询成功
if (target == nums[mid]) {
return mid;
//右区间
} else if (nums[mid] < target) {
left = mid + 1;
//左区间
} else if (nums[mid] > target) {
right = mid - 1;
}
}
//返回插入位置
return left;
}
}
leetcode 34在排序数组中查找元素的第一个和最后一个位置
https://leetcode-cn.com/problems/find-first-and-last-position-of-element-in-sorted-array/
题目描述
给定一个按照升序排列的整数数组 nums,和一个目标值 target。找出给定目标值在数组中的开始位置和结束位置。
如果数组中不存在目标值 target,返回 [-1, -1]。
示例 1:
输入:nums = [5,7,7,8,8,10], target = 8
输出:[3,4]
示例 2:
输入:nums = [5,7,7,8,8,10], target = 6
输出:[-1,-1]
示例 3:
输入:nums = [], target = 0
输出:[-1,-1]
题目解析
们可以使用遍历,当查询到第一个 5 时,我们设立一个指针进行定位,然后到达最后一个 5 时返回,这样我们就能求的第一个和最后一个五了,当然也可以使用二分查找
使用二分查找:
target <= nums[mid] 时,让 right = mid - 1即可,这样我们就可以继续在 mid 的左区间继续找 5 。是不是听着有点绕,我们通过下面这组图进行描述。
其实原理很简单,就是我们将小于和等于合并在一起处理,当 target <= nums[mid] 时,我们都移动右指针,也就是 right = mid -1,还有一个需要注意的就是,我们计算下边界时最后的返回值为 left ,当上图结束循环时,left = 3,right = 2,返回 left 刚好时我们的下边界。我们来看一下求下边界的具体执行过程
变体:找出第一个大于目标元素的索引
所有可能如下:
1.数组包含目标元素,找出在他后面的第一个元素
2.目标元素不在数组中,数组内的部分元素大于它,此时我们需要返回第一个大于他的元素
3.目标元素不在数组中,且数组中的所有元素都大于它,那么我们此时返回数组的第一个元素即可
4.目标元素不在数组中,且数组中的所有元素都小于它,那么我们此时没有查询到,返回 -1 即可。
既然我们已经分析完所有情况,那么这个题目对咱们就没有难度了,下面我们描述一下案例的执行过程
nums = {1,3,5,5,6,6,8,9,11} target = 7
上面的例子中,我们需要找出第一个大于 7 的数,那么我们的程序是如何执行的呢?
public static int lowBoundnum(int[] nums,int target,int left, int right) {
while (left <= right) {
//求中间值
int mid = left + ((right - left) >> 1);
//大于目标值的情况
if (nums[mid] > target) {
//返回 mid
if (mid == 0 || nums[mid-1] <= target) {
return mid;
}
else{
right = mid -1;
}
} else if (nums[mid] <= target){
left = mid + 1;
}
}
//所有元素都小于目标元素
return -1;
}
找出最后一个小于目标元素的索引
通过上面的例子我们应该可以完全理解了那个变种,下面我们继续来看以下这种情况,那就是如何找到最后一个小于目标数的元素。还是上面那个例子
nums = {1,3,5,5,6,6,8,9,11} target = 7
查找最后一个小于目标数的元素,比如我们的目标数为 7 ,此时他前面的数为 6,最后一个 6 的索引为 5,此时我们返回 5 即可,如果目标数元素为 12,那么我们最后一个元素为 11,仍小于目标数,那么我们此时返回 8,即可。这个变种其实算是上面变种的相反情况,上面的会了,这个也完全可以搞定了,下面我们看一下代码吧。
public static int upperBoundnum(int[] nums,int target,int left, int right) {
while (left <= right) {
int mid = left + ((right - left) >> 1);
//小于目标值
if (nums[mid] < target) {
//看看是不是当前区间的最后一位,如果当前小于,后面一位大于,返回当前值即可
if (mid == right || nums[mid+1] >= target) {
return mid;
}
else{
left = mid + 1;
}
} else if (nums[mid] >= target){
right = mid - 1;
}
}
//没有查询到的情况
return -1;
}
寻找最小值
我们见上图,我们需要考虑的情况是
数组完全有序 nums[left] < nums[right],此时返回 nums[left] 即可
left 和 mid 在一个都在前半部分,单调递增区间内,所以需要移动 left,继续查找,left = mid + 1;
left 在前半部分,mid在后半部分,则最小值必在 left 和 mid 之间(见下图)。则需要移动right ,right = mid,我们见上图,如果我们 right = mid - 1,则会漏掉我们的最小值,因为此时 mid 指向的可能就是我们的最小值。所以应该是 right = mid 。
难度中等352收藏分享切换为英文接收动态反馈
假设按照升序排序的数组在预先未知的某个点上进行了旋转。例如,数组
[0,1,2,4,5,6,7]
可能变为[4,5,6,7,0,1,2]
。请找出其中最小的元素。
示例 1:
输入:nums = [3,4,5,1,2] 输出:1示例 2:
输入:nums = [4,5,6,7,0,1,2] 输出:0示例 3:
输入:nums = [1] 输出:1
python3实现如下
def findMin(self, nums: List[int]) -> int:
left = 0
right = len(nums) - 1
# 注意循环条件
while (left <= right):
if (nums[left] <= nums[right]):
return nums[left]
mid = left + ((right - left) >> 1) ## 求mid
if (nums[left] <= nums[mid]):
left = mid + 1
# 右区间
else:
right = mid
return nums[left]
变体二维数组
二维数组
下面我们来看一下另外一种变体,如何在二维矩阵里使用二分查找呢?
其实这个很简单,只要学会了二分查找,这个完全可以解决,我们先来看一个例子
我们需要从一个二维矩阵中,搜索是否含有元素 7,我们如何使用二分查找呢?其实我们可以完全将二维矩阵想象成一个有序的一维数组,然后用二分,,比如我们的二维矩阵中,共有 9 个元素,那定义我们的 left = 0,right = 9 - 1= 8,是不是和一维数组定义相同,然后我们求我们的 mid 值, mid = left +((right - left) >> 1)此时 mid = 4 ,但是我们的二维矩阵下标最大是,nums[2,2]呀,你这求了一个 4 ,让我们怎么整呀。如果我们理解了二分查找,那么这个题目考察我们的应该是如何将一维数组的下标,变为 二维坐标。其实也很简单,咱们看哈,此时咱们的 mid = 4,咱们的二维矩阵共有 3行, 3列,那我们 mid =4,肯定在第二行,那么这个应该怎么求得呢?
我们可以直接用 (mid/列数),即可,因为我们 mid = 4,4 /3 = 1,说明在 在第二行,那如果 mid = 7 ,7/3=2,在第三行,我们第几行知道了,那么我们如何知道第几列呢?我们可以直接根据 (mid % 列数 )来求得呀,比如我们此时 mid = 7,7%3 = 1,那么在我们一维数组索引为 7 的元素,其处于二维数组的第2列,大家看看下图是不是呀!
74https://leetcode-cn.com/problems/search-a-2d-matrix/s/
题目描述
编写一个高效的算法来判断 m x n 矩阵中,是否存在一个目标值。该矩阵具有如下特性:每行中的整数从左到右按升序排列。
每行的第一个整数大于前一行的最后一个整数。示例1
输入:matrix = [[1,3,5,7],[10,11,16,20],[23,30,34,50]], target = 3
输出:true示例2
输入:matrix = [[1,3,5,7],[10,11,16,20],[23,30,34,50]], target = 13
输出:false示例3
输入:matrix = [], target = 0
输出:false
题目解析
在上面我们已经解释了如何在二维矩阵中进行搜索,这里我们再对其进行一个总结,就是我们凭空想象一个一维数组,这个数组是有二维数组一层一层拼接来的,也是完全有序,然后我们定义两个指针一个指向一维数组头部,一个指向尾部,我们求得 mid 值然后将 mid 变成二维坐标,然后和 target 进行比较,如果大于则移动 left ,如果小于则移动 right 。
def searchMatrix(matrix,target):
row,col= len(matrix),len(matrix[0])
left,right=0,row*col-1
# 注意循环条件
while (left <= right):
mid = left + ((right - left) >> 1) ## 求mid
if (matrix[mid//col][mid%col] == target):
return True
elif(matrix[mid//col][mid%col]<target):
left = mid + 1
else:
right = mid - 1
return False
matrix = [[1,3,5,7],[10,11,16,20],[23,30,34,60]]
print( len(matrix),len(matrix[0]))
target = 1
out=searchMatrix(matrix,target)
print('结果:',out)
参考链接:https://leetcode-cn.com/problems/search-in-rotated-sorted-array-ii/solution/yi-wen-dai-ni-gao-ding-er-fen-sou-suo-ji-ki52/
来源:力扣(LeetCode)