zoukankan      html  css  js  c++  java
  • 【LeetCode & 剑指offer刷题】矩阵题3:Kth Smallest Element in a Sorted Matrix

    【LeetCode & 剑指offer 刷题笔记】目录(持续更新中...)

    Kth Smallest Element in a Sorted Matrix

    Given a n x n matrix where each of the rows and columns are sorted in ascending order, find the kth smallest element in the matrix.
    Note that it is the kth smallest element in the sorted order, not the kth distinct element.
    Example:
    matrix = [
    [ 1, 5, 9],
    [10, 11, 13],
    [12, 13, 15]
    ],
    k = 8,
     
    return 13.
    Note: 
    You may assume k is always valid, 1 ≤ k ≤ n2.

    C++
     
    /*
     题目说为 n x n matrix,行列均有序,找出第k小的元素
    方法一:二分查找法整体二分查找,在每行二分查找,统计每行小于等于目标数的个数
    O(logm * nlogn) m为元素个数,行数和列数均为n, 平均logm次计算mid(while语句),每行进行二分查找,时间复杂度为O(nlogn)
     
    注意:一般的二分查找left和right为索引,而这里left,right为元素值,准确来说logm中m应指最大数和最小数的差值。
    (感觉算法不是最优的,有冗余的地方,还是用索引的二分查找法会好一点,mid换算成行列数即可,参见: 4 有序矩阵中的查找(系列 74. Search a 2D Matrix )
    例:
    [1 2
    12 100]
    k = 3
    那么刚开始left = 1, right = 100, mid = 50, 遍历完 cnt = 3,此时right更新为50
    此时left = 1, right = 50, mid = 25, 遍历完之后 cnt = 3, 此时right更新为25
    此时left = 1, right = 25, mid = 13, 遍历完之后 cnt = 3, 此时right更新为13
    此时left = 1, right = 13, mid = 7, 遍历完之后 cnt = 2, 此时left更新为8
    此时left = 8, right = 13, mid = 10, 遍历完之后 cnt = 2, 此时left更新为11
    此时left = 11, right = 12, mid = 11, 遍历完之后 cnt = 2, 此时left更新为12
    循环结束,left和right均为12,任意返回一个即可。
    */
    class Solution
    {
    public:
        int kthSmallest(vector<vector<int>>& matrix, int k)
        {
            int n = matrix.size();
            int left = matrix[0][0], right = matrix[n - 1][n - 1];
            int mid = 0;
            while(left < right) //扫描整个矩阵,这里left,right为值,一般的二分查找为索引
            {
                mid = left + (right-left)/2;
                int count = 0;
                for (int i = 0; i < n; i++) //扫描每行
                {
                    int pos = upper_bound(matrix[i].begin(), matrix[i].end(), mid) - matrix[i].begin(); //用二分查找查找第一个大于目标数的位置,可统计该行中比目标数小的数量
                    count += pos;
                }
                if (count < k) //这里赋left = mid+1和right = mid不是太懂 
                    left = mid + 1//比k小时,left往中间移,增大新mid,增大count
                else
                    right = mid; //比k大或者等于时,right往中间移
            //退出循环时left = right,移动至第k小的元素处
            return left;
        }
    };
     
     
    /*
    方法二:二分查找 + 直接统计法(利用行列有序性)
    我们并不用对每一行都做二分搜索法,我们注意到每列也是有序的,我们可以利用这个性质,依次统计每一列中小于等于目标值的元素数量
    1.从数组的左下角开始查找(i = n-1,j = 0),扫描至矩阵上边界或者右边界,共执行次数最多2n
    2.如果a[i][j] <= target,因为当前元素以上的元素均比目标值小,cnt += i+1,继续下一列的判断(j++);
    3.如果a[i][j] > target,则向上移一位(i--),这样我们也能算出cnt的值。
    复杂度为O(logm * n)
    */
    class Solution {
    public:
        int kthSmallest(vector<vector<int>>& matrix, int k)
        {
            int left = matrix[0][0], right = matrix.back().back();
            while (left < right)
            {
                int mid = left + (right - left) / 2;
                int cnt = search_less_equal(matrix, mid);
                
                if (cnt < k) 
                    left = mid + 1;
                else 
                    right = mid;
            }
            return left;
        }
        int search_less_equal(vector<vector<int>>& matrix, int target)
        {
            int n = matrix.size(), i = n - 1, j = 0, res = 0; //从矩阵左下角开始扫描
            while (i >= 0 && j <= n-1) //如果行或列超出边界就退出循环
            {
                //统计每列小于等于目标值的数量
                if (matrix[i][j] <= target) //当前元素小于或等于目标值
                {
                    res += i + 1; //统计每列小于等于目标值的数量
                    j++; //扫描下一列
                } else //当前元素比目标值大
                {
                    i--; //扫描上一行
                }
            }
            return res;
        }
    };
     
  • 相关阅读:
    201671010115 2016-2017-2《面向对象的程序设计》 Java学习计划
    201671010115 2016-2017-2《Java程序设计》第十八周Java心得
    201671010115 2016-2017-2《面向对象的程序设计》 java 第十六周学习心得
    201671010115 2016-2017-2《Java程序设计》第十五周Java心得
    201671010115 2016-2017-2《面向对象的程序设计》 java第十四周学习心得
    201671010115 2016-2017-2《Java程序设计》第十二周Java心得
    201671010115 2016-2017-2《Java程序设计》第十一周Java心得
    201671010115 2016-2017-2《Java程序设计》第十一周Java心得
    201671010115 2016-2017-2《Java程序设计》第十周Java学习心得
    201671010115 2016-2017-2《Java程序设计》第九周Java心得
  • 原文地址:https://www.cnblogs.com/wikiwen/p/10225014.html
Copyright © 2011-2022 走看看