leetcode 之 二分查找(java)(2)

文章目录

74、搜索二维矩阵

题目描述

给你一个满足下述两条属性的 m x n 整数矩阵:

  • 每行中的整数从左到右按非严格递增顺序排列。
  • 每行的第一个整数大于前一行的最后一个整数。

给你一个整数 target ,如果 target 在矩阵中,返回 true ;否则,返回 false

示例 1:

输入:matrix = [[1,3,5,7],[10,11,16,20],[23,30,34,60]], target = 3
输出:true

示例 2:

输入:matrix = [[1,3,5,7],[10,11,16,20],[23,30,34,60]], target = 13
输出:false

提示:

  • m == matrix.length
  • n == matrix[i].length
  • 1 <= m, n <= 100
  • -104 <= matrix[i][j], target <= 104

思路

首先,题目要求查询target是否在矩阵中,同时矩阵是有序存储的,从左到右,从上到下增大,即右下 > 左上。

target的状态:

情况一、 target在矩阵外,即小于矩阵最小值,大于矩阵最大值。

情况二、target处于矩阵范围内,同时是矩阵内元素,返回true。

情况三、target处于矩阵范围内,但不是矩阵内元素,返回false。

思路:①、我们先遍历矩阵的行,确认target所处的范围是在哪一行,使用idx记录。

​ ②、我们对该行使用二分法,求出target的具体位置。

二分具体实现:

方法1

  • 我们使用全开区间,即(l, r) 表示范围,

  • 令 l = -1, r = n,即恰好在矩阵长度左右范围 + 1,因为是开区间,不包含l和r本身。

  • 同时在循环中加入判断 if(r - l <= 1) break; 因为要判断target恰好在两个数之间,不是矩阵元素的情况。

代码如下:

题解:

java 复制代码
	//方法1
    public boolean searchMatrix(int[][] matrix, int target) {
        int m = matrix.length;
        int n = matrix[0].length;
        
        if(target < matrix[0][0] || target > matrix[m - 1][n - 1]) return false;
        int idx = 0;

        for(int i = 0; i < m; i ++ ) {
            if(matrix[i][n - 1] < target) continue;
            else if(matrix[i][n - 1] >= target) {
                idx = i;
                break;
            }
        }
        // 左开右开区间()
        int l = -1, r = n;
        boolean flag = false;
        while(l < r) {
            int mid = (l + r) / 2;
            if(matrix[idx][mid] > target) r = mid;
            else if(matrix[idx][mid] < target) l = mid;
            else {
                flag = true;
                break;
            }
            if(r - l <= 1) break;
        }
        return flag;
    }

方法2

  • 使用我们使用全闭区间,即[l, r] 表示区间范围。

  • 令l = 0, r = n - 1。因为是闭区间,我们需要包含l和r本身。

  • 闭区间不需要添加判断,因为l和r有 + 1和 - 1的权值变化,最终会自己跳出循环。

代码如下:

java 复制代码
int l = 0, r = n - 1;
boolean flag = false;
while(l <= r) {
    int mid = (l + r) / 2;
    if(matrix[idx][mid] > target) r = mid - 1;
    else if(matrix[idx][mid] < target) l = mid + 1;
    else {
        flag = true;
        break;
    }
}
return flag;

33、搜素旋转排序数组

问题描述

整数数组 nums 按升序排列,数组中的值 互不相同

在传递给函数之前,nums 在预先未知的某个下标 k0 <= k < nums.length)上进行了 旋转 ,使数组变为 [nums[k], nums[k+1], ..., nums[n-1], nums[0], nums[1], ..., nums[k-1]](下标 从 0 开始 计数)。例如, [0,1,2,4,5,6,7] 在下标 3 处经旋转后可能变为 [4,5,6,7,0,1,2]

给你 旋转后 的数组 nums 和一个整数 target ,如果 nums 中存在这个目标值 target ,则返回它的下标,否则返回 -1

你必须设计一个时间复杂度为 O(log n) 的算法解决此问题。

示例 1:

输入:nums = [4,5,6,7,0,1,2], target = 0
输出:4

示例 2:

输入:nums = [4,5,6,7,0,1,2], target = 3
输出:-1

示例 3:

输入:nums = [1], target = 0
输出:-1

提示:

  • 1 <= nums.length <= 5000
  • -104 <= nums[i] <= 104
  • nums 中的每个值都 独一无二
  • 题目数据保证 nums 在预先未知的某个下标上进行了旋转
  • -104 <= target <= 104

思路:

  • 就以[4, 5, 6, 7, 0, 1, 2], target = 8 举例

我们可以明显的看出,如果想要使用二分,就需要找有序的数组,此时我们看到,

  • 该数组有两段局部有序的数组。

  • nums[0]一定大于第二段有序数组的所有数。

我们可以根据第二条性质,使得每次判断都是在有序数组中。

  • 我们实现二分的判断依据就成了,target是否在当前有序数组中,如果不在,那么肯定在该有序数组右(左)边

最开始判断,相等,就直接返回mid.

然后,判断if(nums[0] <= nums[mid])。

  • 这样规定的mid一定处于第一段有序数组中,
    • 内部继续判断if(nums[0] <= target && target < nums[mid]) r = mid - 1
    • else 说明target位于更右边 l = mid + 1

其次,else中

  • 这样的mid一定处于第二段有序数组中,
    • 判断if(nums[mid] < target && target <= nums[n - 1]) l = mid + 1;
    • else 说明target位于更左边 r = mid - 1;

题解

java 复制代码
public int search(int[] nums, int target) {
    if(nums.length == 1) return (nums[0] == target) ? 0 : -1;
    int n = nums.length;
    int l = 0, r = n - 1;

    while(l <= r) {
        int mid = (l + r) / 2;
        if(nums[mid] == target) return mid;
        if(nums[0] <= nums[mid]) {
            if(nums[0] <= target && target < nums[mid]) r = mid - 1;
            else l = mid + 1;
        } else {
            if(nums[mid] < target && target <= nums[n - 1]) l = mid + 1;
            else r = mid - 1;
        }
    }
    return -1;
}
相关推荐
2401_833788051 小时前
Scala的模式匹配(2)
java·开发语言
悠悠龙龙3 小时前
框架模块说明 #05 权限管理_03
java·开发语言·spring
霖大侠3 小时前
Adversarial Learning forSemi-Supervised Semantic Segmentation
人工智能·算法·机器学习
开心羊咩咩3 小时前
Idea 2024.3 突然出现点击run 运行没有反应,且没有任何提示。
java·ide·intellij-idea
waterme1onY3 小时前
IDEA中MAVEN的一些设置问题
java·maven·intellij-idea
阿华的代码王国3 小时前
【算法】——前缀和(矩阵区域和详解,文末附)
java·开发语言·算法·前缀和
Sunyanhui13 小时前
力扣 LCR训练计划2(剑指 Offer 22. 链表中倒数第k个节点)-140
算法·leetcode·链表
yours_Gabriel4 小时前
【力扣】3274. 检查棋盘方格颜色是否相同
算法·leetcode
Chandler244 小时前
蓝桥杯经验分享
经验分享·算法·蓝桥杯
是老余4 小时前
算法基础之链表:移除链表元素leetcode203
数据结构·算法·链表