二分法搜索行列有序矩阵系列

leetcode378有序矩阵中第K小的元素[1]

给定一个 n x n 矩阵,其中每行和每列元素均按升序排序,找到矩阵中第 k 小的元素。
请注意,它是排序后的第 k 小元素,而不是第 k 个不同的元素.

 

示例:

matrix = [
   [ 1,  5,  9],
   [10, 11, 13],
   [12, 13, 15]
],
k = 8,

返回 13。

 

提示:
你可以假设 k 的值永远是有效的,1 ≤ k ≤ n2 。

因为是有序数组查找,首先想到的就是二分法。首先确定查找范围,low=matrix[0][0],high=matrix[n-1][n-1],第k小元素一定在[low, high]区间。每次对区间二分,查找<=mid的元素个数cnt,若cnt

按照上述思路,实现代码如下:

    int kthSmallest(vector>& matrix, int k) {
        int n = matrix.size();
        int low = matrix[0][0], high = matrix[n-1][n-1];
        while (low

1)对于num_le(matrix,mid)函数,比较容易想到的思路是对matrix按行/列二分,查找第一个>mid的位置,例如第i行第一个>mid的元素是matrix[i][p],cnt+=p。

int num_le(vector>& a, int target)
{
    int cnt = 0;      
    for (int i = 0; i < matrix.size(); ++i) 
        # c++自带函数upper_bound(),返回>target的第一个元素位置。也可以自己实现二分查找
        cnt += upper_bound(matrix[i].begin(), matrix[i].end(), mid) - matrix[i].begin();
        
    return cnt;
            
};

设m=(high-low), 这种实现方式的时间复杂度为O(logm*n*logn)。

2)可以发现,前面那种按行/列二分实现num_le()的方法实际上是利用了矩阵行升序的性质,而没有用到列升序这一性质。怎么利用矩阵列升序排列这一性质来降低时间复杂度呢?对于矩阵元素matrix[i][j],可以发现,上方元素都小于等于它,右方元素都大于等于它。如果我们从左下角matrix[n-1][0]开始遍历,若当前元素>target,需要向上查找i--;否则cnt+=i, 且j++。这种实现方式的时间复杂度为O(logm*2n)=O(nlogm)。

int num_le(vector>& a, int target)
    {
        int n = a.size();
        int i=n-1, j=0, cnt=0;
        while (i>=0 && jtarget)
                i--;  //向上查找更小的元素
            else
            {
                cnt += (i+1);  //当前列(0-i)行的元素均满足<=target
                j++;     //向右查找更大的元素
            }
        }
        return cnt;
    }
};

240. 搜索二维矩阵 I

 

编写一个高效的算法来搜索 m x n 矩阵 matrix 中的一个目标值 target。该矩阵具有以下特性:

  • 每行的元素从左到右升序排列。
  • 每列的元素从上到下升序排列。

    示例:

    现有矩阵 matrix 如下:

    [
      [1,   4,  7, 11, 15],
      [2,   5,  8, 12, 19],
      [3,   6,  9, 16, 22],
      [10, 13, 14, 17, 24],
      [18, 21, 23, 26, 30]
    ]


    给定 target = 5,返回 true。

    给定 target = 20,返回 false.

  •  

    1)与前面思路一致,可以采用按行二分查找,但时间复杂度为O(m*logn)

    2)从左下角开始遍历,当前元素>target,则向上搜索,  

        bool searchMatrix(vector>& matrix, int target) {
            int m = matrix.size();
            if (m==0)   return false;
            int n = matrix[0].size();
            int i = m-1, j = 0;
            while (i>=0 && j target)
                    i--;
                else if (matrix[i][j] < target)
                    j++;
                else
                    return true;
            }
            return false;
        }

     

[1]https://leetcode-cn.com/problems/kth-smallest-element-in-a-sorted-matrix

[2]https://leetcode-cn.com/problems/search-a-2d-matrix-ii/

你可能感兴趣的:(c++,#二分法)