Idiot-maker

  :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::

https://leetcode.com/problems/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.

 

For example,

Consider the following matrix:

[
  [1,   3,  5,  7],
  [10, 11, 16, 20],
  [23, 30, 34, 50]
]

Given target = 3, return true.

解题思路:

这道题属于常规思路,两次二分查找。首先二分查找应该在的行,然后再在该行内做一次标准的二分查找。

如果matrix[mid][0] > target,说明要找的数比mid行第一个数小,那么一定在mid行以前。如果matrix[mid][0] < target,说明target比mid行第一个数字大,那么有可能就在mid行,也有可能在mid行往后的行。

这时就通过对比mid行最后一个数字和target的大小来判断。

public class Solution {
    public boolean searchMatrix(int[][] matrix, int target) {
        int start = 0;
        int end = matrix.length - 1;
        int row = -1;
        
        while(start <= end){
            int mid = (start + end) / 2;
            if(matrix[mid][0] == target){
                return true;
            }
            if(matrix[mid][0] > target){
                end = mid - 1;
            }
            if(matrix[mid][0] < target){
                if(matrix[mid][matrix[mid].length - 1] == target){
                    return true;
                }
                if(matrix[mid][matrix[mid].length - 1] > target){
                    row = mid;
                    break;
                }
                if(matrix[mid][matrix[mid].length - 1] < target){
                    start = mid + 1;
                }
            }
        }
        if(row == -1){
            return false;
        }
        
        start = 0;
        end = matrix[row].length - 1;
        while(start <= end){
            int mid = (start + end) / 2;
            if(matrix[row][mid] == target){
                return true;
            }
            if(matrix[row][mid] < target){
                start = mid + 1;
            }
            if(matrix[row][mid] > target){
                end = mid - 1;
            }
        }
        return false;
    }
}

 后来看到网友在第一次二分搜索,即搜索行的时候,有比较简洁,但需要理解一下的方法。就是直接用end作为最后的行。我们看看如何证明?

假设有行4、22、35、47、89、100、120,我们想找90,应该在89那一行。第一次mid=47,于是start到了89那一行。然后mid=100,于是end=89。这时start=end=89。要找90,start++,到了100。循环退出。

可以看到end正好在要找的那一行,而start则超过了一行。

为什么会这样?因为end是当target<mid的时候更新的,如果target存在,最后一次搜索一定是start=end=mid落在target所在行,target只可能>mid,所以只会更新start++。这样最终end一定在target所在的行上,除非end减到最后已经为-1了。

public class Solution {
    public boolean searchMatrix(int[][] matrix, int target) {
        int start = 0;
        int end = matrix.length - 1;
        int row = -1;
        
        while(start <= end){
            int mid = (start + end) / 2;
            if(matrix[mid][0] == target){
                return true;
            }
            if(matrix[mid][0] > target){
                end = mid - 1;
            }
            if(matrix[mid][0] < target){
                start = mid + 1;
            }
        }
        
        row = end;
        if(row == -1){
            return false;
        }
        
        start = 0;
        end = matrix[0].length - 1;
        while(start <= end){
            int mid = (start + end) / 2;
            if(matrix[row][mid] == target){
                return true;
            }
            if(matrix[row][mid] < target){
                start = mid + 1;
            }
            if(matrix[row][mid] > target){
                end = mid - 1;
            }
        }
        return false;
    }
}

这道题本身不难,但是对理解二分查找的过程,特别是两端指针更新的条件和结果,循环的过程,还是比较好的。

posted on 2015-03-10 21:35  NickyYe  阅读(188)  评论(0编辑  收藏  举报