优化排序矩阵中第 N 个最大元素的代码
Posted
技术标签:
【中文标题】优化排序矩阵中第 N 个最大元素的代码【英文标题】:Optimize code for Nth largest element in sorted matrix 【发布时间】: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 我从来没有想过你提出的解决方案!但是是的,这些值可以重复。
【参考方案1】:
回应评论:即使有重复的元素,我认为没有必要使用复杂的数据结构,如优先级队列和映射,甚至内部类。我认为应该可以简单地从数组的末尾开始,走到数组的开头,然后计算值更改的频率。从值“infinity”(或此处为Integer.MAX_VALUE
)开始,在k
th 值更改后,一个具有k
th 最大元素。
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 好的,就我的理解而言,最后一个不是“排序”的。也许很难给出一个精确的问题陈述和有代表性的测试用例,但它可能是必要的(至少有人期望一个精确和有用的答案)以上是关于优化排序矩阵中第 N 个最大元素的代码的主要内容,如果未能解决你的问题,请参考以下文章