LintCode 28: Search a 2D Matrix (Binary Searh经典题)

本文探讨了在有序二维矩阵中高效查找特定值的三种方法。包括两次二分查找、将矩阵视为一维数组进行二分查找及从右上角开始逐行逐列逼近目标的策略。
  1. Search a 2D Matrix
    Write an efficient algorithm that searches for a value in an m x n matrix.

This matrix has the following properties:

Integers in each row are sorted from left to right.
The first integer of each row is greater than the last integer of the previous row.
Example
Consider the following matrix:

[
[1, 3, 5, 7],
[10, 11, 16, 20],
[23, 30, 34, 50]
]
Given target = 3, return true.

Challenge
O(log(n) + log(m)) time

解法1:两次Binary Search。第1次找到相应Row, 第2次在Row里面找target。

class Solution {
public:
    /**
     * @param matrix: matrix, a list of lists of integers
     * @param target: An integer
     * @return: a boolean, indicate whether matrix contains target
     */
    bool searchMatrix(vector<vector<int>> &matrix, int target) {
        int nRow = matrix.size();
        if (nRow == 0) return false;
        int nCol = matrix[0].size();
        
        if ((target < matrix[0][0]) || (target > matrix[nRow - 1][nCol - 1])) return false;
        
        vector<int> col0(nRow, 0);
        
        for (int i = 0; i < nRow; ++i) {
            col0[i] = matrix[i][0];
        }
        

        int indexRow = binarySearch(col0, 0, nRow - 1, target);

        int indexCol = binarySearch(matrix[indexRow], 0, nCol - 1, target);

        if (target == matrix[indexRow][indexCol]) return true;
        else return false;
    }
    
    // find the index of the first element that is smaller or equal to target
    int binarySearch(vector<int> nums, int start, int end, int target) {
        if (nums.size() == 0 || start > end) return -1;
        
        while (start + 1 < end) {
            int mid = start + (end - start) / 2;
            if (nums[mid] == target) {
                return mid;
            } else if (nums[mid] < target) {
                start = mid;
            } else { 
                end = mid;
            }
        }
        
        if (nums[start] == target) return start;
        if (nums[end] == target) return end;

        if (nums[end] < target) return end;        
        if (nums[start] < target) return start;
        return -1;
    } 
};

解法2:将整个matrix视为一个一维array,因为下面两个条件决定了当m个行数组挨个连起来后的一维array仍然是单调递增(严格说是单调不递减)。所以用binary search即可。
Integers in each row are sorted from left to right.
The first integer of each row is greater than the last integer of the previous row.
注意:这题与LintCode 38 Search a 2D Matrix II不一样,那题的条件是行对应元素递增,列对应元素递增,但若将m个行数组穿起来的一维数组则未必单调递增。也就是说本题的条件更严格。
但虽然本题解法不实用于LintCode 38,LintCode 38的解法倒适用于本题。因为本题更严格。见解法3。
代码如下:

class Solution {
public:
    /**
     * @param matrix: matrix, a list of lists of integers
     * @param target: An integer
     * @return: a boolean, indicate whether matrix contains target
     */
    bool searchMatrix(vector<vector<int>> &matrix, int target) {
        int m = matrix.size();
        if (m == 0) return false;
        int n = matrix[0].size();
        if (n == 0) return false;
        
        int start = 0, end = m * n - 1;
        while(start + 1 < end) {
            int mid = start + (end - start) / 2;
            int row = mid / n;
            int col = mid % n;
            if (matrix[row][col] < target) {
                start = mid;
            } else if (matrix[row][col] > target) {
                end = mid;
            } else {
                return true;
            }
        }
        if (matrix[start / n][start % n] == target) return true;
        if (matrix[end / n][end % n] == target) return true;
        return false;
    }
};

解法3:即LintCode 38的解法。从右上角开始,每次行+1或列-1,直到找到target。代码如下:

class Solution {
public:
    /**
     * @param matrix: matrix, a list of lists of integers
     * @param target: An integer
     * @return: a boolean, indicate whether matrix contains target
     */
    bool searchMatrix(vector<vector<int>> &matrix, int target) {
        int m = matrix.size();
        if (m == 0) return false;
        
        int n = matrix[0].size();
        if (n == 0) return false;
        
        int count = 0;
        int row = 0;
        int col = n - 1;  //start from the right top point
        
        while (row < m && col >= 0) {
            if (matrix[row][col] > target) {
                col--;
            } else if (matrix[row][col] < target) {
                row++;
            } else {
                return true;
            }
        }

        return matrix[count / n][count % n] == target;    
    }
};

二刷,好像上面的 return matrix[count / n][count % n] == target; 不需要

class Solution {
public:
    /**
     * @param matrix: matrix, a list of lists of integers
     * @param target: An integer
     * @return: a boolean, indicate whether matrix contains target
     */
    bool searchMatrix(vector<vector<int>> &matrix, int target) {
        int nRow = matrix.size();
        if (nRow == 0) return false;
        int nCol = matrix[0].size();
        if (nCol == 0) return false;
        int row = 0, col = nCol -1;
        while (row < nRow && col >= 0) {
            if (matrix[row][col] > target) {
                col -= 1;
            } else if (matrix[row][col] < target) {
                row += 1;
            } else {
                return true;
            }
        }
        return false;
    }
};



评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值