leetcode-搜索总结

leetcode-278-第一个错误的版本(first bad version)-java
二分查找法中,mid不能用
int mid=(begin+last)/2;
要用
int mid=begin+(last-begin)/2; 也可以(begin+end)>>>1
因为第一种情况begin+last可能会溢出,导致出错

leetcode-215-数组中的第K个最大元素 (kth largest element in an array)-java
查找-数组中的第K个最大元素
方法1:
使用最小堆的方法,求第k大,建立一个规模为k的最小堆
首先将nums前k个元素加入堆,然后初始化最小堆,让heap[0]为这k个元素小的
然后将nums第k到length-1个,依次与heap[0]比较
如果比它大,则替代heap【0】,然后下沉,让heap[0]继续是这k个最小的
所以最后,heap为nums中前k大的,heap[0]为第k大的
该方法速度为o(nlogk),比全部排序o(nlogn)快

方法2:
利用快速排序的思想,在进行排序过程中每次可以确定一个元素的最终位置,若此位置为第K个最大元素,则直接返回此索引,否则继续分治进行快速排序。不用排列全部,只要每次只排序一段,找到即可

leetcode-162-寻找峰值(find peak element)-java
解法1:
直接顺序查找,看now>prev&&now>next即可
解法2:
在简单的二分查找中,我们处理的是一个有序数列,并通过在每一步减少搜索空间来找到所需要的数字。在本例中,我们对二分查找进行一点修改。首先从数组 nums 中找到中间的元素 mid。
若该元素恰好位于降序序列或者一个局部下降坡度中(通过将 nums[i] 与右侧比较判断),则说明峰值会在本元素的左边。于是,我们将搜索空间缩小为 mid的左边(包括其本身),并在左侧子数组上重复上述过程。
若该元素恰好位于升序序列或者一个局部上升坡度中(通过将 nums[i]与右侧比较判断),则说明峰值会在本元素的右边。于是,我们将搜索空间缩小为 mid的右边,并在右侧子数组上重复上述过程。

就这样,我们不断地缩小搜索空间,直到搜索空间中只有一个元素,该元素即为峰值元素。
**最左端和最右端元素均无限小,中间元素比两侧都要大,那么本题中一定存在一个峰元素。**所以不管中间有多少波峰,只要找到峰元素,我们只需找到刚刚开始下降而未下降的位置。采用二分查找,查出这样一个位置即可,我们知道二分查找要比较的是 target 元素,本题的 target 元素是 mid 的后一个元素,即 nums[mid] 与 nums[mid+1] 进行比较:

leetcode-34-在排序数组中查找元素的第一个和最后一个位置(find first and last position of element in sorted array)-java
解法:
先将target与nums[0]进行比较,得到target在前半段还是后半段,然后进行二分查找,将now与nums[0]进行判断,判断now在前半段还是后半段,如果不是target对应的波段,直接缩小范围,如果是target对应的波段,直接安装二分查找的方法进行查找。

leetcode-240-搜索二维矩阵 II(search a 2ds matrix 2)-java
从矩阵的正对角线的两端,他们的两个方向都是都变大或变小,从反对角线的两端,方向是一个变大,一个变小,就可以根据大小,向相应的方向跑过去,直到遇到或者超出矩阵的边界
首先判断(rows-1,0)处的元素,记为x,如果给定的target>x,则延行方向向右寻找,否则延列方向向上寻找。

leetcode-378-有序矩阵中第K小的元素-java
解法1
使用容量为k的最大堆。

解法2
思路非常简单:
1.找出二维矩阵中最小的数left,最大的数right,那么第k小的数必定在left~right之间
2.mid=(left+right) / 2;在二维矩阵中寻找小于等于mid的元素个数count
3.若这个count小于k,表明第k小的数在右半部分且不包含mid,即left=mid+1, right=right,又保证了第k小的数在left~right之间
4.若这个count大于k,表明第k小的数在左半部分且可能包含mid,即left=left, right=mid,又保证了第k小的数在left~right之间
5.因为每次循环中都保证了第k小的数在left~right之间,当left==right时,第k小的数即被找出,等于right
注意:这里的left mid right是数值,不是索引位置。

leetcode-4-寻找两个有序数组的中位数-java
解法1
可以一半儿一半儿的排除。假设我们要找第 k 小数,我们可以每次循环排除掉 k/2 个数。看下边一个例子。
比较1349,12345678910
我们比较两个数组的第 k/2 个数字,如果 k 是奇数,向下取整。也就是比较第 3 个数字,上边数组中的 4 和下边数组中的 3,如果哪个小,就表明该数组的前 k/2 个数字都不是第 k 小数字,所以可以排除。也就是 1,2,3这三个数字不可能是第 7小的数字,我们可以把它排除掉。将 1349 和 45678910 两个数组作为新的数组进行比较。
更一般的情况 A[1] ,A[2] ,A[3],A[k/2] … ,B[1],B[2],B[3],B[k/2] … ,如果 A[k/2] A 数组中比 A[k/2] 小的数有 k/2-1 个,B 数组中,B[k/2] 比 A[k/2] 小,假设 B[k/2] 前边的数字都比 A[k/2] 小,也只有 k/2-1 个,所以比 A[k/2] 小的数字最多有 k/1-1+k/2-1=k-2个,所以 A[k/2] 最多是第 k-1 小的数。而比 A[k/2] 小的数更不可能是第 k 小的数了,所以可以把它们排除。
比较1349,(123)45678910
由于我们已经排除掉了 3 个数字,就是这 3 个数字一定在最前边,所以在两个新数组中,我们只需要找第 7 - 3 = 4 小的数字就可以了,也就是 k = 4。此时两个数组,比较第 2 个数字,3 < 5,所以我们可以把小的那个数组中的 1 ,3 排除掉了。
比较(13)49,(123)45678910
我们又排除掉 2 个数字,所以现在找第 4 - 2 = 2 小的数字就可以了。此时比较两个数组中的第 k / 2 = 1 个数,4 == 4,怎么办呢?由于两个数相等,所以我们无论去掉哪个数组中的都行,因为去掉 1 个总会保留 1 个的,所以没有影响。为了统一,我们就假设 4 > 4 吧,所以此时将下边的 4 去掉。
比较(13)49,(1234)5678910
由于又去掉 1 个数字,此时我们要找第 1 小的数字,所以只需判断两个数组中第一个数字哪个小就可以了,也就是 4。
所以第 7 小的数字是 4。

解法2
一个长度为 m 的数组,有 0 到 m 总共 m + 1 个位置可以切。
我们把数组 A 和数组 B 分别在 i 和 j 进行切割。
将 i 的左边和 j 的左边组合成「左半部分」,将 i 的右边和 j 的右边组合成「右半部分」。
当 A 数组和 B 数组的总长度是偶数时,如果我们能够保证
左半部分的长度等于右半部分
i + j = m - i + n - j , 也就是 j = ( m + n ) / 2 - i
左半部分最大的值小于等于右半部分最小的值 max ( A [ i - 1 ] , B [ j - 1 ])) <= min ( A [ i ] , B [ j ]))
那么,中位数就可以表示如下
(左半部分最大值 + 右半部分最小值 )/ 2。
(max ( A [ i - 1 ] , B [ j - 1 ])+ min ( A [ i ] , B [ j ])) / 2
当 A 数组和 B 数组的总长度是奇数时,如果我们能够保证
左半部分的长度比右半部分大 1
i + j = m - i + n - j + 1也就是 j = ( m + n + 1) / 2 - i
左半部分最大的值小于等于右半部分最小的值 max ( A [ i - 1 ] , B [ j - 1 ])) <= min ( A [ i ] , B [ j ]))
那么,中位数就是
左半部分最大值,也就是左半部比右半部分多出的那一个数。
max ( A [ i - 1 ] , B [ j - 1 ])
上边的第一个条件我们其实可以合并为 j=(m+n+1)/2−i,因为如果 m+n是偶数,由于我们取的是 int 值,所以加 1 也不会影响结果。当然,由于 0<=i<=m ,为了保证 0<=j<=n,我们必须保证 m<=n。
m≤n,i(m+m+1)/2−m=0
m≤n,i>0,j=(m+n+1)/2−i≤(n+n+1)/2−i<(n+n+1)/2=n
最后一步由于是 int 间的运算,所以 1/2=0
而对于第二个条件,奇数和偶数的情况是一样的,我们进一步分析。为了保证 max ( A [ i - 1 ] , B [ j - 1 ])) <= min ( A [ i ] , B [ j ])),因为 A 数组和 B 数组是有序的,所以 A [ i - 1 ] <= A [ i ],B [ i - 1 ] <= B [ i ] 这是天然的,所以我们只需要保证 B [ j - 1 ] < = A [ i ] 和 A [ i - 1 ] <= B [ j ] 所以我们分两种情况讨论:
B [ j - 1 ] > A [ i ],并且为了不越界,要保证 j != 0,i != m
此时很明显,我们需要增加 i ,为了数量的平衡还要减少 j ,幸运的是 j = ( m + n + 1) / 2 - i,i 增大,j 自然会减少。
A [ i - 1 ] > B [ j ] ,并且为了不越界,要保证 i != 0,j != n
此时和上边的情况相反,我们要减少 i ,增大 j 。

你可能感兴趣的:(leetcode总结,算法-搜索)