矩阵查找

矩阵查找

http://www.nowcoder.com/questionTerminal/5145394607ea4c5f8b25755718bfddba

本篇内容虽多,但有助于系统构建对二分查找的知识体系,如果您还不能闭着眼睛写二分的话,建议仔细看看哦~

二分查找是一个思路很简单、但实现起来有点恼人的算法。正所谓知己知彼,胜乃不怠;知天知地,胜乃不穷,我们先对二分法这个“敌人”做一个简单的分类:

  1. 按查找区间分类——闭区间[..]左闭右开区间[..)
  2. 按具体任务分类——寻找特定值寻找左侧边界寻找右侧边界

寻找特定值

给定一个有序数组,如[1, 2, 5, 8, 9, 13, 19, 20, 68],查找19的位置:

int binarySearch(vector<int> array, int target) {
    int left = 0, right = array.size() - 1;  // ☢︎☢︎☢︎

    while (left <= right) {                  // ☢︎☢︎☢︎
        int mid = left + (right-left)/2;     // ☢︎☢︎☢︎
        if (array[mid] < target) left = mid + 1;
        else if (array[mid] > target) right = mid - 1;
        else if (array[mid] == target) return mid;
    }

    return -1;
}

框架的☢︎☢︎☢︎部分是尤其需要我们注意的,这里我们选取的是在闭区间[..]内查找,因此right=array.size()-1,且循环条件为left <= right;另外的话mid = left + (right-left)/2,这么写比mid = (left+right)/2要好,可以防止left+right溢出。

如果您想在开区间内查找,这么改即可:右侧端点变成right = array.size()、循环条件变为left < right

寻找左侧边界

给定数组[1, 3, 5, 6, 6, 6, 8, 7],找出6的左侧边界:

int binarySearch(vector<int> array, int target) {
    if (array.size() < 1) return -1;

    int left = 0, right = array.size() - 1;
    while (left <= right) {
        int mid = left + (right-left) / 2;
        if (array[mid] > target) right = mid - 1;
        else if (array[mid] < target) left = mid + 1;
        else if (array[mid] == target) right = mid - 1; // ☢︎☢︎☢︎
    }

    // ☢︎☢︎☢︎
    if (left >= array.size() || array[left] != target) return -1;
    else return left;
}

总体上和二分法寻找特定值一致,但是注意标记了☢︎☢︎☢︎的部分:

  1. array[mid] == target,我们需要设置right = mid - 1
  2. 循环结束后,需要判断left是否越过右边界,或者left位置对应的值不等于target

如果问题是寻找右侧边界,我们只需要在寻找左侧边界基础上改改即可:①当array[mid] == target时,设置left = mid + 1; ②循环结束后,判断right是否越过左边界,或者right位置对应的值不等于target.

本题思路与代码

用两次二分法,第一次定位所在行,第二次定位所在列,代码如下:

//
// Created by jt on 2020/9/3.
//
#include <vector>
using namespace std;

class Solution {
public:
    /**
     *
     * @param matrix int整型vector<vector<>>
     * @param target int整型
     * @return bool布尔型
     */
    bool searchMatrix(vector<vector<int> >& matrix, int target) {
        // write code here
        if (matrix.size() < 1 || matrix[0].size() < 1) return false;
        int row = matrix.size(), col = matrix[0].size();
        // 第一步:定位所在行
        int left = 0, right = row - 1, midRow;
        while (left <= right) {
            midRow = left + (right-left) / 2;
            if (matrix[midRow][0] > target)  right = midRow - 1;
            else if (matrix[midRow][col-1] < target) left = midRow + 1;
            else if (matrix[midRow][0] == target || matrix[midRow][col-1] == target) return true;
            else if (matrix[midRow][0] < target && matrix[midRow][col-1] > target) break;
        }
        if (left > right) return false; // 越界
        left = 0, right = col - 1;
        int midCol;
        // 第二步:定位所在列
        while (left <= right) {
            midCol = left + (right-left) / 2;
            if (matrix[midRow][midCol] > target) right = midCol - 1;
            else if (matrix[midRow][midCol] < target) left = midCol + 1;
            else if (matrix[midRow][midCol] == target) return true;
        }
        return false;
    }
};
刷遍天下无敌手 文章被收录于专栏

秋招刷题历程

全部评论
将操作抽象出来,岂不是更能很好的套用二分 private int[][] matrix=null; private int end; public boolean searchMatrix (int[][] matrix, int target) { // write code here if(matrix==null) return false; if(matrix.length==0) return false; this.matrix=matrix; this.end=matrix.length*matrix[0].length; if(this.end==1) { if(matrix[0][0]==target) { return true; }else { return false; } } return halfsearch(target,1,end); } public int lengthTox(int length) { return (length-1)/this.matrix[0].length; } public int lengthToy(int length) { return length-lengthTox(length)*this.matrix[0].length-1; } public int xyTolength(int x,int y) { return x*this.matrix[0].length+y+1; } public boolean halfsearch(int target,int left,int right) { //边界条件 if(target>this.matrix[lengthTox(right)][lengthToy(right)]||target<this.matrix>this.matrix[lengthTox(mid)][lengthToy(mid)]){ left=mid; } if(target</this.matrix>
1
送花
回复
分享
发布于 2021-02-22 01:15
请问大佬,开区间内查找为什么‘循环条件变为left < right’,这样不对吧,比如说在列表[1,2]中查找1
点赞
送花
回复
分享
发布于 2021-06-01 00:46
秋招专场
校招火热招聘中
官网直投
没想到还有人和我总结的二分法一样哈哈哈 都用<=
点赞
送花
回复
分享
发布于 2021-07-01 10:09

相关推荐

祈求顺利毕业😁:简历很好了,多投吧牛油😂。主要是环境不好,大家也卷
点赞 评论 收藏
转发
4 收藏 评论
分享
牛客网
牛客企业服务