优化排序矩阵中第N个最大元素的代码

时间:2014-06-13 14:29:03

标签: java algorithm sorting data-structures matrix

我有一个排序矩阵中第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循环改为了

    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);
    }

如果我们对列感到筋疲力尽,那么在我们从其他列中找到元素之前,我们不再添加任何项目。

这也适用于矩阵,它只按行排序但不按列排序。

1 个答案:

答案 0 :(得分:1)

回应评论:即使有重复的元素,我也不认为有必要使用复杂的数据结构,如优先级队列和地图,甚至是内部类。我认为应该可以简单地从数组的末尾开始,走到数组的开头,并计算值的变化频率。从价值&#34;无限&#34;开始(或Integer.MAX_VALUE此处),k值更改后,其中一个元素具有k个最大元素。

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;
    }

}