二分查找(simple难度)
https://leetcode-cn.com/problems/binary-search/
class Solution {
public int binarySearch(int[] nums, int target) {
int len = nums.length;
int left = 0;
int right = len - 1;//注意,左闭右闭区间,所以right = len - 1
// 目标元素可能在 左闭右闭 区间:[left, right],但下面while循环是 < 而不是 <= ,要注意
while (left < right) {
int mid = left + (right - left) / 2;
if (nums[mid] < target) {
// 下一轮搜索区间是 [mid + 1, right],索引mid对应元素一定不符合要求,所以左边界是mid+1
left = mid + 1;
} else {
// 下一轮搜索区间是 [left, mid],索引mid对应元素可能不符合要求,所以右边界是mid
right = mid;
}
}
if (nums[left] == target) {
return left;
}
return -1;
}
}
或者:
class Solution {
public int binarySearch(int[] nums, int target) {
int len = nums.length;
int left = 0;
int right = len - 1;
// 定义target在 左闭右闭 的区间里,[left, right]
//若if (nums[mid] == target) 在while内判断,则是left <= right
//若不在while内判断相等时的情况,则是left < right
while (left <= right) {// 当left==right,区间[left, right]依然有效
int mid = left + (right - left) / 2; //防止溢出,等同于(left + right)/2
if (nums[mid] == target) {
return mid;
} else if (nums[mid] < target) {
//因为target要在左闭右闭的区间里,因为nums[mid]不满足条件,
//所以要把mid从区间里剔除,所以搜索区间变为[mid + 1, right]
left = mid + 1; // target在右区间,所以[mid + 1, right]
} else {
right = mid - 1; // target在左区间,所以[left, mid - 1]
}
}
return -1;
}
}
第一个错误的版本(simple难度)
https://leetcode-cn.com/problems/first-bad-version/
/* The isBadVersion API is defined in the parent class VersionControl.
boolean isBadVersion(int version); */
public class Solution extends VersionControl {
public int firstBadVersion(int n) {
int left = 1;
int right = n;
while (left < right){
int mid = left + (right - left) / 2;
if(isBadVersion(mid) == false){
left = mid + 1;
}else{
right = mid;
}
}
return left;
}
}
猜数字大小(simple难度)
https://leetcode-cn.com/problems/guess-number-higher-or-lower/
/**
* Forward declaration of guess API.
* @param num your guess
* @return -1 if num is lower than the guess number
* 1 if num is higher than the guess number
* otherwise return 0
* int guess(int num);
*/
public class Solution extends GuessGame {
public int guessNumber(int n) {
int left = 1;
int right = n;
while (left <= right) {
int mid = left + (right - left) / 2;
if(guess(mid) == 0){
return mid;
}else if(guess(mid) == -1){
right = mid - 1;
}else{
left = mid + 1;
}
}
return left;
}
}
排列硬币(simple难度)
https://leetcode-cn.com/problems/arranging-coins/
排列硬币可以转化成寻找 <=n
的最大等差数列和的尾项。
细节看代码注释。
class Solution {
public int arrangeCoins(int n) {
long left = 0;
long right = n;
while (left < right) {
long mid = left + (right - left + 1) / 2;
//硬币排列类似等差数列求和
//等差数列求和公式:(首项 + 尾项) * 项数 / 2
//本题中首项为1,尾项为mid,项数也为mid
//本题要满足:(首项 + 尾项) * 项数 / 2 <= n
//整理可得:mid * (mid + 1) <= 2 * n
if (mid * (mid + 1) > (long) 2 * n) {
right = mid - 1;
} else {
left = mid;
}
}
return (int) left;
}
}
搜索插入位置(simple难度)
https://leetcode-cn.com/problems/search-insert-position/
class Solution {
public int searchInsert(int[] nums, int target) {
int n = nums.length;
int left = 0;
int right = n - 1; // 定义target在左闭右闭的区间里,[left, right]
while (left <= right) { // 当left==right,区间[left, right]依然有效
int mid = left + ((right - left) / 2);// 防止溢出 等同于(left + right)/2
if (nums[mid] > target) {
right = mid - 1; // target 在左区间,所以[left, mid - 1]
} else if (nums[mid] < target) {
left = mid + 1; // target 在右区间,所以[mid + 1, right]
} else { // nums[mid] == target
return mid;
}
}
// 分别处理如下四种情况
// 目标值在数组所有元素之前 [0, -1]
// 目标值等于数组中某一个元素 return mid;
// 目标值插入数组中的位置 [left, right],return right + 1
// 目标值在数组所有元素之后的情况 [left, right], return right + 1
return right + 1;
}
}
或:
public class Solution {
public int searchInsert(int[] nums, int target) {
int len = nums.length;
if (len == 0) {
return 0;
}
// 特判
if (nums[len - 1] < target) {
return len;
}
int left = 0;
int right = len - 1;
while (left < right) {
int mid = left + (right - left) / 2;
// 严格小于 target 的元素一定不是解
if (nums[mid] < target) {
// 下一轮搜索区间是 [mid + 1, right]
left = mid + 1;
} else {
// 下一轮搜索区间是 [left, mid]
right = mid;
}
}
return left;
}
}
在排序数组中查找元素的第一个和最后一个位置(medium)
https://leetcode-cn.com/problems/find-first-and-last-position-of-element-in-sorted-array/
本题方法和代码来源:
作者:liweiwei1419
链接:https://leetcode-cn.com/problems/find-first-and-last-position-of-element-in-sorted-array/solution/si-lu-hen-jian-dan-xi-jie-fei-mo-gui-de-er-fen-cha/
来源:力扣(LeetCode)
class Solution {
public int[] searchRange(int[] nums, int target) {
int len = nums.length;
if (len == 0) {
return new int[]{-1, -1};
}
//firstPosition == -1 说明数组中没有target,则返回[-1,-1]
int firstPosition = findFirstPosition(nums, target);
if (firstPosition == -1) {
return new int[]{-1, -1};
}
int lastPosition = findLastPosition(nums, target);
return new int[]{firstPosition, lastPosition};
}
//查找相同target值的左边界
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) {
// 下一轮搜索区间是 [mid + 1, right]
left = mid + 1;
} else if (nums[mid] == target) {
// 下一轮搜索区间是 [left, mid],一直向左搜寻,找到左边界
right = mid;
} else {
// nums[mid] > target,下一轮搜索区间是 [left, mid - 1]
right = mid - 1;
}
}
if (nums[left] == target) {
return left;
}
return -1;
}
//查找相同target值的右边界
private int findLastPosition(int[] nums, int target) {
int left = 0;
int right = nums.length - 1;
while (left < right) {
int mid = left + (right - left + 1) / 2;
if (nums[mid] > target) {
// 下一轮搜索区间是 [left, mid - 1]
right = mid - 1;
} else if (nums[mid] == target){
// 下一轮搜索区间是 [mid, right],一直向右搜寻,找到右边界
left = mid;
} else {
// nums[mid] < target,下一轮搜索区间是 [mid + 1, right]
left = mid + 1;
}
}
return left;
}
}
作者:liweiwei1419
链接:https://leetcode-cn.com/problems/find-first-and-last-position-of-element-in-sorted-array/solution/si-lu-hen-jian-dan-xi-jie-fei-mo-gui-de-er-fen-cha/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
搜索旋转排序数组(medium难度)
https://leetcode-cn.com/problems/search-in-rotated-sorted-array/
<方法一>:
本题方法和代码来源:
作者:sweetiee
链接:https://leetcode-cn.com/problems/search-in-rotated-sorted-array/solution/duo-si-lu-wan-quan-gong-lue-bi-xu-miao-dong-by-swe/
来源:力扣(LeetCode)
<方法二>:
本题方法和代码来源:
作者:liweiwei1419
链接:https://leetcode-cn.com/problems/search-in-rotated-sorted-array/solution/er-fen-fa-python-dai-ma-java-dai-ma-by-liweiwei141/
来源:力扣(LeetCode)
让情况1和情况2保持一致不然选不出中位数
public class Solution {
public int search(int[] nums, int target) {
int len = nums.length;
if (len == 0) {
return -1;
}
int left = 0;
int right = len - 1;
while (left < right) {
int mid = left + (right - left + 1) / 2;
if (nums[mid] < nums[right]) {
// 使用上取整的中间数,必须在上面的 mid 表达式的括号里 + 1
if (nums[mid] <= target && target <= nums[right]) {
// 下一轮搜索区间是 [mid, right]
left = mid;
} else {
// 只要上面对了,这个区间是上面区间的反面区间,下一轮搜索区间是 [left, mid - 1]
right = mid - 1;
}
} else {
// [left, mid] 有序,但是为了和上一个 if 有同样的收缩行为,
// 我们故意只认为 [left, mid - 1] 有序
// 当区间只有 2 个元素的时候 int mid = (left + right + 1) >>> 1; 一定会取到右边
// 此时 mid - 1 不会越界,就是这么刚刚好
if (nums[left] <= target && target <= nums[mid - 1]) {
// 下一轮搜索区间是 [left, mid - 1]
right = mid - 1;
} else {
// 下一轮搜索区间是 [mid, right]
left = mid;
}
}
}
// 有可能区间内不存在目标元素,因此还需做一次判断
if (nums[left] == target) {
return left;
}
return -1;
}
}
作者:liweiwei1419
链接:https://leetcode-cn.com/problems/search-in-rotated-sorted-array/solution/er-fen-fa-python-dai-ma-java-dai-ma-by-liweiwei141/
来源:力扣(LeetCode)
class Solution5 {
public int 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) {
return mid;
}
// 先根据 nums[mid] 与 nums[left] 的关系判断 mid 是在左段还是右段
// mid 是在左段
//循环条件是 left<=right, 所以 mid 会等于 left
if (nums[mid] >= nums[left]) {
// 再判断 target 是在 mid 的左边还是右边,从而调整左右边界 left 和 right
// target 是在mid的左边,开区间
if (target >= nums[left] && target < nums[mid]) {
right = mid - 1;
} else {
left = mid + 1;
}
// mid 是在右段
} else {
if (target > nums[mid] && target <= nums[right]) {
left = mid + 1;
} else {
right = mid - 1;
}
}
}
return -1;
}
}
搜索旋转排序数组Ⅱ(medium难度)
https://leetcode-cn.com/problems/search-in-rotated-sorted-array-ii/
本题方法和代码来源:
作者:liweiwei1419
链接:https://leetcode-cn.com/problems/search-in-rotated-sorted-array-ii/solution/er-fen-cha-zhao-by-liweiwei1419/
来源:力扣(LeetCode)
本题数组不完全有序且含有重复元素
本题不能采用LeetCode33.搜索旋转排序数组的代码的原因如下图:
class Solution {
public boolean search(int[] nums, int target) {
int len = nums.length;
if (len == 0) {
return false;
}
int left = 0;
int right = len - 1;
while (left < right) {
int mid = (left + right) >>> 1;
if (nums[mid] > nums[left]) { //mid处在没被旋转的子数组中,[left,mid]有序,包括mid
if (nums[left] <= target && target <= nums[mid]) {
// 落在前有序数组[left,mid]里
right = mid;
// 落在后数组[mid+1,right]里
left = mid + 1;
}
} else if (nums[mid] < nums[left]) { //此时mid处于被旋转的子数组中,[mid,right]有序
// 让分支和上面分支一样
if (nums[mid] < target && target <= nums[right]) {
//落在后数组[mid+1,right]里
left = mid + 1;
} else {
//落在前数组[left,mid]里
right = mid;
}
} else {
// nums[mid] == nums[left],此时要去掉重复元素。要排除掉左边界之前,先看一看左边界可以不可以排除
if (nums[left] == target) {
return true;
} else {
left = left + 1;
}
}
}
// 后处理,夹逼以后,还要判断一下,是不是 target
return nums[left] == target;
}
}
作者:liweiwei1419
链接:https://leetcode-cn.com/problems/search-in-rotated-sorted-array-ii/solution/er-fen-cha-zhao-by-liweiwei1419/
来源:力扣(LeetCode)
public class Solution {
// 中间的数与右边界比较
public boolean search(int[] nums, int target) {
int len = nums.length;
if (len == 0) {
return false;
}
int left = 0;
int right = len - 1;
while (left < right) {
int mid = (left + right + 1 ) >>> 1;
if (nums[mid] < nums[right]) {
// 10 11 4 5 6 7 8 9
// 右边的一定是顺序数组,包括中间数
if (nums[mid] <= target && target <= nums[right]) {
left = mid;
} else {
right = mid - 1;
}
} else if (nums[mid] > nums[right]) {
// 4 5 9 2
// 左边是一定是顺序数组,包括中间数
if (nums[left] <= target && target < nums[mid]) {
right = mid - 1;
} else {
left = mid;
}
}else {
if(nums[right] == target){
return true;
}
right = right -1;
}
}
return nums[left] == target;
}
}
作者:liweiwei1419
链接:https://leetcode-cn.com/problems/search-in-rotated-sorted-array-ii/solution/er-fen-cha-zhao-by-liweiwei1419/
来源:力扣(LeetCode)
寻找旋转排序数组中的最小值(medium难度)
https://leetcode-cn.com/problems/find-minimum-in-rotated-sorted-array/
class Solution {
public int findMin(int[] nums) {
int left = 0;
int right = nums.length - 1;
while (left < right) {
int mid = left + (right - left) / 2; // 防止溢出
//nums[mid]可能是最小值,所以区间缩小为[left,mid]
if (nums[mid] < nums[right]) {
right = mid;
}else{
//nums[mid] > nums[right]时,
//nums[mid]不可能是最小值,所以区间缩小为[mid + 1.rght]
left = mid + 1;
}
}
return nums[left];
}
}
作者:HIT_whc
链接:https://leetcode-cn.com/problems/find-minimum-in-rotated-sorted-array/solution/javaji-jian-er-fen-cha-zhao-shi-jian-ji-oiefi/
来源:力扣(LeetCode)
寻找旋转排序数组中的最小值Ⅱ(hard难度)
https://leetcode-cn.com/problems/find-minimum-in-rotated-sorted-array-ii/
在上道题LeetCode153.寻找旋转排序数组中的最小值的题解的基础上,把nums[mid] == nums[right]
单独拿出来考虑,并进行收缩边界。这样做的原因详见代码注释,在代码注释中结合力扣测试用例进行了说明。
class Solution {
public int findMin(int[] nums) {
int left = 0;
int right = nums.length - 1;
while (left < right) {
int mid = left + (right - left) / 2;
//[mid,right]升序,最小值在[left,mid]
if (nums[mid] < nums[right]) {
right = mid;
//最小值在[mid+1,right]
} else if (nums[mid] > nums[right]) {
left = mid + 1;
} else {
//nums[mid] == nums[right],有重复元素,
//此时不好判断最小值在哪边,所以收缩右边界,去掉一个重复元素
//例如[3,3,1,3],left=0,right=3,mid=0,,nums[mid] == nums[right],
//若采用right = mid收缩边界,则[left,right]区间元素变成[3,3],错过最小值
//例如[1,3,3]left=0,right=2,mid=1,nums[mid] == nums[right]
//若left = mid + 1收缩边界,[left,right]区间元素变成[3],错过最小值
right--;
}
}
return nums[left];
}
}
作者:HIT_whc
链接:https://leetcode-cn.com/problems/find-minimum-in-rotated-sorted-array-ii/solution/javaji-jian-er-fen-cha-zhao-zhong-fu-yua-glhs/
来源:力扣(LeetCode)
本题方法和代码来源:
作者:jyd
链接:https://leetcode-cn.com/problems/find-minimum-in-rotated-sorted-array-ii/solution/154-find-minimum-in-rotated-sorted-array-ii-by-jyd/
来源:力扣(LeetCode)
class Solution {
public int findMin(int[] nums) {
int left = 0, right = nums.length - 1;
while (left < right) {
int mid = (left + right) / 2;
if (nums[mid] > nums[right]) left = mid + 1;
else if (nums[mid] < nums[right]) right = mid;
else right = right - 1;
}
return nums[left];
}
}
作者:jyd
链接:https://leetcode-cn.com/problems/find-minimum-in-rotated-sorted-array-ii/solution/154-find-minimum-in-rotated-sorted-array-ii-by-jyd/
来源:力扣(LeetCode)
山脉数组的峰顶索引(simple难度)
class Solution {
public int peakIndexInMountainArray(int[] arr) {
int left = 0;
int right = arr.length - 1;
while (left < right) {
int mid = left + (right - left + 1) / 2;
if (arr[mid] > arr[mid - 1]) {
left = mid;
} else {//arr[mid] < arr[mid - 1]
right = mid - 1;
}
}
return left;
}
}
或:
public int peakIndexInMountainArray(int[] A) {
// 1.[定左右]
int l = 0;
int r = A.length-1;
// 2.[定区间]
while (l <= r) {// [l,r]
// 3.[取中值]
int mid = l + (r-l)/2;
// 4.[进退]
if (A[mid+1] > A[mid]) {// 上坡
l = mid + 1; // [爬坡]
} else if (A[mid-1] > A[mid]){// 下坡
r = mid - 1; // [返回坡顶]
} else {
return mid;
}
}
// 5.[无功而返]
return -1;
}
作者:CVBear
链接:https://leetcode-cn.com/problems/peak-index-in-a-mountain-array/solution/man-hua-suan-fa-er-fen-cha-zhao-yi-shou-shi-jie-ju/
来源:力扣(LeetCode)
x的平方根(simple难度)
https://leetcode-cn.com/problems/sqrtx/
<方法一>:二分查找
class Solution {
public int mySqrt(int x) {
if (x == 0) {
return 0;
}
long left = 1;
long right = x;
while (left < right) {
long mid = left + (right - left + 1) / 2;
if ( mid * mid <= x) {
left = mid;
} else {
right = mid - 1;
}
}
return (int)left;
}
}
<方法二>:牛顿迭代
本方法思路和代码来源:
作者:LOAFER
链接:https://leetcode-cn.com/problems/sqrtx/solution/niu-dun-die-dai-fa-by-loafer/
来源:力扣(LeetCode)
class Solution {
int s;
public int mySqrt(int x) {
s=x;
if(x==0) return 0;
return ((int)(sqrts(x)));
}
public double sqrts(double x){
double res = (x + s / x) / 2;
if (res == x) {
return x;
} else {
return sqrts(res);
}
}
}
作者:LOAFER
链接:https://leetcode-cn.com/problems/sqrtx/solution/niu-dun-die-dai-fa-by-loafer/
来源:力扣(LeetCode)
有效的完全平方数(simple难度)
https://leetcode-cn.com/problems/valid-perfect-square/
class Solution {
public boolean isPerfectSquare(int num) {
long left = 0;
long right = num;
while (left < right) {
long mid = left + (right - left + 1) / 2;
long sum = mid * mid;
if (sum <= num) {
left = mid;
} else {
right = mid - 1;
}
}
return (left*left) == num;
}
}
寻找右区间(medium难度)
https://leetcode-cn.com/problems/find-right-interval/
本题方法和代码来源:
作者:liweiwei1419
链接:https://leetcode-cn.com/problems/find-right-interval/solution/er-fen-cha-zhao-hong-hei-shu-by-liweiwei1419/
来源:力扣(LeetCode)
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
public class Solution {
public int[] findRightInterval(int[][] intervals) {
int len = intervals.length;
if (len == 0) {
return new int[0];
}
// 对原始区间进行预处理,key:起点,value:索引
// 题目中说:你可以假定这些区间都不具有相同的起始点
Map<Integer, Integer> hashMap = new HashMap<>(len);
int[] arr = new int[len];
int[] res = new int[len];
for (int i = 0; i < len; i++) {
hashMap.put(intervals[i][0], i);
arr[i] = intervals[i][0];
}
Arrays.sort(arr);
for (int i = 0; i < len; i++) {
int index = binarySearch(arr, intervals[i][1]);
if (index == -1) {
res[i] = -1;
} else {
res[i] = hashMap.get(arr[index]);
}
}
return res;
}
/**
* 查找第 1 个大于等于 target 的元素的索引
*
* @param arr
* @param target
* @return
*/
private int binarySearch(int[] arr, int target) {
int len = arr.length;
// 特判
if (arr[len - 1] < target) {
return -1;
}
int left = 0;
int right = len - 1;
while (left < right) {
int mid = (left + right) >>> 1;
if (arr[mid] < target) {
left = mid + 1;
} else {
right = mid;
}
}
return left;
}
}
作者:liweiwei1419
链接:https://leetcode-cn.com/problems/find-right-interval/solution/er-fen-cha-zhao-hong-hei-shu-by-liweiwei1419/
来源:力扣(LeetCode)
import java.util.Arrays;
import java.util.Map;
import java.util.TreeMap;
public class Solution2 {
public int[] findRightInterval(int[][] intervals) {
int len = intervals.length;
if (len == 0) {
return new int[0];
}
TreeMap<Integer, Integer> treeMap = new TreeMap<>();
int[] res = new int[len];
for (int i = 0; i < len; i++) {
treeMap.put(intervals[i][0], i);
}
for (int i = 0; i < len; i++) {
Map.Entry<Integer, Integer> entry = treeMap.ceilingEntry(intervals[i][1]);
if (entry == null) {
res[i] = -1;
} else {
res[i] = entry.getValue();
}
}
return res;
}
}
作者:liweiwei1419
链接:https://leetcode-cn.com/problems/find-right-interval/solution/er-fen-cha-zhao-hong-hei-shu-by-liweiwei1419/
来源:力扣(LeetCode)
寻找峰值(medium难度)
https://leetcode-cn.com/problems/find-peak-element/
本题方法和代码来源:
作者:guanpengchn
链接:https://leetcode-cn.com/problems/find-peak-element/solution/hua-jie-suan-fa-162-xun-zhao-feng-zhi-by-guanpengc/
来源:力扣(LeetCode)
class Solution {
public int findPeakElement(int[] nums) {
int left = 0, right = nums.length - 1;
for (; left < right; ) {
int mid = left + (right - left) / 2;
if (nums[mid] > nums[mid + 1]) {
right = mid;
} else {
left = mid + 1;
}
}
return left;
}
}
作者:guanpengchn
链接:https://leetcode-cn.com/problems/find-peak-element/solution/hua-jie-suan-fa-162-xun-zhao-feng-zhi-by-guanpengc/
来源:力扣(LeetCode)
搜索二维矩阵(medium难度)
https://leetcode-cn.com/problems/search-a-2d-matrix/
class Solution {
public boolean searchMatrix(int[][] matrix, int target) {
int targetRow = binarySearch(target, matrix);
int left = 0;
int right = matrix[targetRow].length - 1;
//横向二分查找找到target所在的列
while (left < right) {
int mid = left + (right - left) / 2;
if (matrix[targetRow][mid] < target) {
left = mid + 1;
} else {
right = mid;
}
}
return matrix[targetRow][left] == target;
}
//先纵向二分查找找到target所在的行
private int binarySearch(int target, int[][] matrix) {
int left = 0;
int right = matrix.length - 1;
int column = matrix[0].length - 1;
while (left < right) {
int mid = left + (right - left) / 2;
if (matrix[mid][column] < target) {
left = mid + 1;
} else {
right = mid;
}
}
return left;
}
}
作者:HIT_whc
链接:https://leetcode-cn.com/problems/search-a-2d-matrix/solution/javaheng-xiang-zong-xiang-liang-ci-er-fe-v5v0/
来源:力扣(LeetCode)
搜索二维矩阵Ⅱ(medium难度)
https://leetcode-cn.com/problems/search-a-2d-matrix-ii/
本题方法和代码来源:
作者:liweiwei1419
链接:https://leetcode-cn.com/problems/search-a-2d-matrix-ii/solution/er-fen-fa-pai-chu-fa-python-dai-ma-java-dai-ma-by-/
来源:力扣(LeetCode)
public class Solution {
public boolean searchMatrix(int[][] matrix, int target) {
int rows = matrix.length;
if (rows == 0) {
return false;
}
int cols = matrix[0].length;
if (cols == 0) {
return false;
}
// 起点:左下角
int x = rows - 1;
int y = 0;
// 不越界的条件是:行大于等于 0,列小于等于 cols - 1
while (x >= 0 && y < cols) {
// 打开注释,可以用于调试的代码
// System.out.println("沿途走过的数字:" + matrix[x][y]);
if (matrix[x][y] > target) {
x--;
} else if (matrix[x][y] < target) {
y++;
} else {
return true;
}
}
return false;
}
}
作者:liweiwei1419
链接:https://leetcode-cn.com/problems/search-a-2d-matrix-ii/solution/er-fen-fa-pai-chu-fa-python-dai-ma-java-dai-ma-by-/
来源:力扣(LeetCode)
public class Solution {
public boolean searchMatrix(int[][] matrix, int target) {
// 特判
int rows = matrix.length;
if (rows == 0) {
return false;
}
int cols = matrix[0].length;
if (cols == 0) {
return false;
}
// 起点:右上角
int x = 0;
int y = cols - 1;
// 不越界的条件是:行小于等于 rows - 1,列大于等于 0
while (x < rows && y >= 0) {
// 打开注释,可以用于调试的代码
// System.out.println("沿途走过的数字:" + matrix[x][y]);
if (matrix[x][y] > target) {
y--;
} else if (matrix[x][y] < target) {
x++;
} else {
return true;
}
}
return false;
}
}
作者:liweiwei1419
链接:https://leetcode-cn.com/problems/search-a-2d-matrix-ii/solution/er-fen-fa-pai-chu-fa-python-dai-ma-java-dai-ma-by-/
来源:力扣(LeetCode)
class Solution {
private int diagonalBinarySearch(int[][] matrix, int diagonal, int target) {
int left = 0;
int right = diagonal;
while (left < right) {
int mid = (left + right) >>> 1;
if (matrix[mid][mid] < target) {
left = mid + 1;
} else {
right = mid;
}
}
return left;
}
// 下面两个二分查找没有使用模板,因为只是找一个数,而不是找这个数的边界
// 用教科书上的二分查找法更简单
private boolean rowBinarySearch(int[][] matrix, int begin, int cols, int target) {
int left = begin;
int right = cols;
while (left <= right) {
int mid = (left + right) >>> 1;
if (matrix[begin][mid] == target) {
return true;
} else if (matrix[begin][mid] < target) {
left = mid + 1;
} else {
right = mid - 1;
}
}
return false;
}
private boolean colBinarySearch(int[][] matrix, int begin, int rows, int target) {
// 这里可以 + 1
int left = begin + 1;
int right = rows;
while (left <= right) {
int mid = (left + right) >>> 1;
if (matrix[mid][begin] == target) {
return true;
} else if (matrix[mid][begin] < target) {
left = mid + 1;
} else {
right = mid - 1;
}
}
return false;
}
public boolean searchMatrix(int[][] matrix, int target) {
// 特判
int rows = matrix.length;
int cols = matrix[0].length;
int minVal = Math.min(rows, cols);
// 沿着对角线搜索第 1 个大于等于 target 的数的索引
int index = diagonalBinarySearch(matrix, minVal - 1, target);
if (matrix[index][index] == target) {
return true;
}
// 沿着对角线朝两边搜索
for (int i = 0; i <= index; i++) {
// 行搜索传入列总数 - 1
boolean rowSearch = rowBinarySearch(matrix, i, cols - 1, target);// 列搜索传入行总数 - 1
boolean colSearch = colBinarySearch(matrix, i, rows - 1, target);
if (rowSearch || colSearch) {
return true;
}
}
return false;
}
}
分割数组的最大值(hard难度)
https://leetcode-cn.com/problems/split-array-largest-sum/
本题方法和代码来源:
作者:liweiwei1419
链接:https://leetcode-cn.com/problems/split-array-largest-sum/solution/er-fen-cha-zhao-by-liweiwei1419-4/
来源:力扣(LeetCode)
public class Solution {
public int splitArray(int[] nums, int m) {
int max = 0;
int sum = 0;
// 计算「子数组各自的和的最大值」的上下界
for (int num : nums) {
max = Math.max(max, num);
sum += num;
}
// 使用「二分查找」确定一个恰当的「子数组各自的和的最大值」,
// 使得它对应的「子数组的分割数」恰好等于 m
int left = max;
int right = sum;
while (left < right) {
int mid = left + (right - left) / 2;
int splits = split(nums, mid);
if (splits > m) {
// 如果分割数太多,说明「子数组各自的和的最大值」太小,此时需要将「子数组各自的和的最大值」调大
// 下一轮搜索的区间是 [mid + 1, right]
left = mid + 1;
} else {
// 下一轮搜索的区间是上一轮的反面区间 [left, mid]
right = mid;
}
}
return left;
}
/***
*
* @param nums 原始数组
* @param maxIntervalSum 子数组各自的和的最大值
* @return 满足不超过「子数组各自的和的最大值」的分割数
*/
private int split(int[] nums, int maxIntervalSum) {
// 至少是一个分割
int splits = 1;
// 当前区间的和
int curIntervalSum = 0;
for (int num : nums) {
// 尝试加上当前遍历的这个数,如果加上去超过了「子数组各自的和的最大值」,就不加这个数,另起炉灶
if (curIntervalSum + num > maxIntervalSum) {
curIntervalSum = 0;
splits++;
}
curIntervalSum += num;
}
return splits;
}
}
作者:liweiwei1419
链接:https://leetcode-cn.com/problems/split-array-largest-sum/solution/er-fen-cha-zhao-by-liweiwei1419-4/
来源:力扣(LeetCode)
寻找两个正序数组的中位数
代码:
public class Solution {
public double findMedianSortedArrays(int[] nums1, int[] nums2) {
if (nums1.length > nums2.length) {
int[] temp = nums1;
nums1 = nums2;
nums2 = temp;
}
int m = nums1.length;
int n = nums2.length;
// 分割线左边的所有元素需要满足的个数 m + (n - m + 1) / 2;
int totalLeft = (m + n + 1) / 2;
// 在 nums1 的区间 [0, m] 里查找恰当的分割线,
// 使得 nums1[i - 1] <= nums2[j] && nums2[j - 1] <= nums1[i]
int left = 0;
int right = m;
while (left < right) {
int i = left + (right - left + 1) / 2;
int j = totalLeft - i;
if (nums1[i - 1] > nums2[j]) {
// 下一轮搜索的区间 [left, i - 1]
right = i - 1;
} else {
// 下一轮搜索的区间 [i, right]
left = i;
}
}
int i = left;
int j = totalLeft - i;
int nums1LeftMax = i == 0 ? Integer.MIN_VALUE : nums1[i - 1];
int nums1RightMin = i == m ? Integer.MAX_VALUE : nums1[i];
int nums2LeftMax = j == 0 ? Integer.MIN_VALUE : nums2[j - 1];
int nums2RightMin = j == n ? Integer.MAX_VALUE : nums2[j];
if (((m + n) % 2) == 1) {
return Math.max(nums1LeftMax, nums2LeftMax);
} else {
return (double) ((Math.max(nums1LeftMax, nums2LeftMax) + Math.min(nums1RightMin, nums2RightMin))) / 2;
}
}
}
作者:liweiwei1419
链接:https://leetcode-cn.com/problems/median-of-two-sorted-arrays/solution/he-bing-yi-hou-zhao-gui-bing-guo-cheng-zhong-zhao-/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。