【问题标题】:Optimize code for Nth largest element in sorted matrix优化排序矩阵中第 N 个最大元素的代码
【发布时间】:2014-06-13 14:29:03
【问题描述】:

我有一个排序矩阵中第 n 个最大元素的代码(按行和列递增的顺序排序)

我在执行代码中的 (findNextElement) 部分时遇到了一些问题 即,如果该行已用尽,则向上一行并获取其中的下一个元素。

我已经做到了,但是代码看起来有点复杂。 (我的代码可以正常工作并正确生成输出)我将在这里发布我的代码

k 是第 K 个最大的元素 m, n 是矩阵维度(目前只支持 NxN 矩阵,但可以修改为支持 MxN)

public int findkthLargestElement(int[][] input, int k, int m, int n) {
    if (m <=1 || n <= 1 || k > m * n) {
        return Integer.MIN_VALUE;
    }
    int i = 0;
    int j = 0;
    if (k < m && k < n) {
        i = m - k;
        j = n - k;
    }
    PriorityQueue<Element> maxQueue = new PriorityQueue(m, new Comparator<Element>() {
        @Override
        public int compare(Element a, Element b) {
            return b.value - a.value;
        }
    });

    Map<Integer, Integer> colMap = new HashMap<Integer, Integer>();
    for (int row = i; row < m; row++) {
        Element e = new Element(input[row][n - 1], row, n - 1);
        colMap.put(row, n - 1);
        maxQueue.add(e);
    }
    Element largest = new Element(0, 0, 0);
    for (int l = 0; l < k; l++) {
        largest = maxQueue.poll();
        int row = largest.row;
        colMap.put(row, colMap.get(row) - 1);
        int col = colMap.get(row);
        while (col < j && row > i) {
            row = row - 1;
            colMap.put(row, colMap.get(row) - 1);
            col = Math.max(0, colMap.get(row));
        }

        Element nextLargest = new Element(input[row][Math.max(0, col)], row, Math.max(0, col));
        maxQueue.add(nextLargest);
    }
    return largest.value;

}

我在 for 循环中需要一些帮助,请建议我一个更好的方法来完成任务。

我的代码在这里运行 http://ideone.com/wIeZSo

好的,我找到了一种简单有效的方法来完成这项工作,我将 for 循环更改为 ths

    for (int l = 0; l < k; l++) {
        largest = maxQueue.poll();
        int row = largest.row;
        colMap.put(row, colMap.get(row) - 1);
        int col = colMap.get(row);
        if (col < j) {
            continue;
        }
        Element nextLargest = new Element(input[row][Math.max(0, col)], row, Math.max(0, col));
        maxQueue.add(nextLargest);
    }

如果我们对某一列感到筋疲力尽,那么我们不会再添加任何项目,直到我们从其他列中找到一个元素。

这也适用于仅按行而非按列排序的矩阵。

【问题讨论】:

  • 你或许应该解释一下为什么这个方法的实现可能只是int i=m*n-1-(k-1);return input[i/n][i%n];。很可能是因为矩阵中可能有 相等 个元素...?
  • @Marco13 我从来没有想过你提出的解决方案!但是是的,这些值可以重复。

标签: java algorithm sorting data-structures matrix


【解决方案1】:

回应评论:即使有重复的元素,我认为没有必要使用复杂的数据结构,如优先级队列和映射,甚至内部类。我认为应该可以简单地从数组的末尾开始,走到数组的开头,然后计算值更改的频率。从值“infinity”(或此处为Integer.MAX_VALUE)开始,在kth 值更改后,一个具有kth 最大元素。

public class KthLargestElementTest
{
    public static void main (String[] args) throws java.lang.Exception
    {
        testDistinct();
        testNonDistinct();
        testAllEqual();
    }

    private static void testDistinct()
    {
        System.out.println("testDistinct");
        int[][] input = new int[][] 
        {
            {1, 2, 3, 4},
            {8, 9, 10, 11},
            {33, 44, 55, 66},
            {99, 150, 170, 200}
        };
        for (int i = 1; i <= 17; i ++) 
        {
            System.out.println(findkthLargestElement(input, i, 4, 4));  
        }
    }

    private static void testNonDistinct()
    {
        System.out.println("testNonDistinct");
        int[][] input = new int[][]
        {
            { 1, 1, 1, 4 },
            { 4, 4, 11, 11 },
            { 11, 11, 66, 66 },
            { 66, 150, 150, 150 } 
        };
        for (int i = 1; i <= 6; i++)
        {
            System.out.println(findkthLargestElement(input, i, 4, 4));
        }
    }    

    private static void testAllEqual()
    {
        System.out.println("testAllEqual");
        int[][] input = new int[][]
        {
            { 4, 4, 4, 4 },
            { 4, 4, 4, 4 },
            { 4, 4, 4, 4 },
            { 4, 4, 4, 4 } 
        };
        for (int i = 1; i <= 2; i++)
        {
            System.out.println(findkthLargestElement(input, i, 4, 4));
        }
    }    

    public static int findkthLargestElement(
        int[][] input, int k, int m, int n) 
    {
        int counter = 0;
        int i=m*n-1;
        int previousValue = Integer.MAX_VALUE;
        while (i >= 0)
        {
            int value = input[i/n][i%n];
            if (value < previousValue)
            {
                counter++;
            }
            if (counter == k)
            {
                return value;
            }
            previousValue = value;
            i--;
        }
        if (counter == k)
        {
            return input[0][0];
        }
        System.out.println("There are no "+k+" different values!");
        return Integer.MAX_VALUE;
    }

}

【讨论】:

  • 谢谢!我想我已经超越了自己并实现了 K 方式合并来处理仅按列排序的矩阵。例如1,2,3 9,10,11 4,5,6
  • 我认为你的代码会在这个int[][] i = {{10, 20, 30, 40}, {15, 25, 35, 45}, {24, 29, 37, 48}, {32, 33, 39, 50}};上中断
  • @jay 好的,就我的理解而言,最后一个不是“排序”的。也许很难给出一个精确的问题陈述和有代表性的测试用例,但它可能是必要的(至少有人期望一个精确和有用的答案)
猜你喜欢
  • 2013-02-17
  • 2015-06-24
  • 2020-09-06
  • 2011-02-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多