我有一个int [] []矩阵,我想根据矩阵中的值将coords存储在不同的数组中。 我认为我的解决方案有效,但效果不是很好......
public ArrayList<ArrayList<Coords>> storeValues(int[][] labels) {
int max = getMaxValue(labels);
ArrayList<ArrayList<Coords>> collection = new ArrayList<ArrayList<Coords>>();
ArrayList<Coords> coords;
while (max > 0) {
coords = new ArrayList<Coords>();
for (int x = 0; x < labels.length; x++) {
for (int y = 0; y < labels[0].length; y++) {
if (max == labels[x][y]) {
coords.add(new Coords(x,y));
}
}
}
collection.add(coords);
--max;
}
return collection;
}
private int getMaxValue(int[][] labels) {
int max = labels[0][0];
for (int tabValue[] : labels) {
for (int value : tabValue) {
if (max < value) {
max = value;
}
}
}
return max;
}
例如:
我的矩阵包含
[ [ 0, 0, 0 ],
[ 1, 1, 1 ],
[ 1, 2, 2 ],
[ 2, 2, 5 ] ]
预期结果
ArrayList{
ArrayList{ Coord[0,0], Coord[1,0], Coord[2,0] }, // list of 0 value
ArrayList{ Coord[0,1], Coord[1,1], Coord[2,1], Coord[0,3] }, // list of 1 value
...
}
答案 0 :(得分:2)
您的目标应该是尽可能少地迭代。如果使用Map构建所需的数据结构,实际上可以在单个(嵌套)迭代中执行此操作。这里最有用的是TreeMap
,因为它会按键自动排序..
逻辑是,而不是嵌套列表,构建new TreeMap<Integer, ArrayList<Coords>>
。
Integer-key是您的值,arrayList是该值的Coords列表。
您像以前一样迭代矩阵,但不计算max
。这样可以节省整个getMaxValue
方法和外部while循环。
对于每个值,首先检查TreeMap
是否包含具有该键的条目。如果是,请将新Coord
添加到map.get(val)。如果不是,请创建new ArrayList<Coord>
,将您的Coord
添加到该列表中,然后将其放入地图中。
如果你绝对必须拥有ArrayList&gt;作为返回类型,您可以使用return new ArrayList<ArrayList<Coord>>(map.values())
答案 1 :(得分:1)
我同意您当前的算法可能效果不佳。如果您说矩阵的维度为M*N
,则运行时分析可能如下所示:
max_val = get_max_val(); // O(M*N)
for i from max_val to 0: // O(max_val)
// O(M*N)
for x from 0 to M:
for y from 0 to N:
do_stuff;
换句话说,这适用于O(M*N*max_val)
。如果max_val
非常大,这很危险;特别是因为实际的算法不 依赖于这些值是什么(只是哪些是相同的)。
替代算法,仅取决于M
和N
:
HashMap<Integer, ArrayList<Coords>> coordsMap = new HashMap<Integer, ArrayList<Coords>>();
for (int i = 0; i < labels.length; i++) {
for (int j = 0; j < labels[i].length; j++) {
if (coordsMap.containsKey(labels[i][j])) {
ArrayList<Coords> coords = coordsMap.get(labels[i][j]);
coordsMap.put(labels[i][j], coords.add(new Coords(i, j));
}
}
}
// collect results
ArrayList<ArrayList<Coords>> coordsList = new ArrayList<ArrayList<Coords>>();
for (Integer label : coordsMap.keySet()) {
coordsList.add(coordsMap.get(label));
}
return coordsList;
此时的运行时为M*N*(HashMap get/put time)
。
如果你想为每个值from 0 to max_val
都有一个ArrayList,其中缺少带有该标签的坐标由空ArrayList表示,你可以将// collect results
部分改为: / p>
// collect results
for (int i = 0; i < max_val; i++) {
if (coordsMap.containsKey(i)) {
coordsList.add(coordsMap.get(i));
}
else {
coordsList.add(new ArrayList<Coords>());
}
}
正如Marco13对您的问题的评论所暗示的那样,实际表现可能在一定程度上取决于您的数据实际外观。
答案 2 :(得分:1)
当值已经排序时,解决方案非常简单:只需遍历矩阵(按排序顺序),并在遇到新值时始终创建新列表。
当值不排序时,您可以创建一个坐标列表,按相应的值对它们进行排序,然后对它进行相同的方法,就像对已排序的情况一样。
这两个版本都在这里实现:
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
public class SortMatrixCoordinates
{
static class Coords
{
int x;
int y;
Coords(int x, int y)
{
this.x = x;
this.y = y;
}
@Override
public String toString()
{
return "("+x+","+y+")";
}
}
public static void main(String[] args)
{
runWithSortedMatrix();
runWithUnsortedMatrix();
}
private static void runWithSortedMatrix()
{
int labels[][] = new int[][]{
{ 0, 0, 0 },
{ 1, 1, 1 },
{ 1, 2, 2 },
{ 2, 2, 5 } };
System.out.println("Result with sorted matrix:");
List<List<Coords>> result = storeValues(labels);
for (List<Coords> list : result)
{
System.out.println(list);
}
}
private static void runWithUnsortedMatrix()
{
int labels[][] = new int[][]{
{ 0, 0, 0 },
{ 3, 3, 3 },
{ 3, 2, 2 },
{ 2, 2, 1 } };
System.out.println("Result with unsorted matrix:");
List<List<Coords>> result = storeValuesSorting(labels);
for (List<Coords> list : result)
{
System.out.println(list);
}
}
public static List<List<Coords>> storeValues(final int[][] labels)
{
List<List<Coords>> result = new ArrayList<List<Coords>>();
List<Coords> coords = null;
int previousValue = 0;
for (int x = 0; x < labels.length; x++)
{
for (int y = 0; y < labels[0].length; y++)
{
int value = labels[x][y];
if ((x == 0 && y == 0) || previousValue != value)
{
coords = new ArrayList<Coords>();
result.add(coords);
}
coords.add(new Coords(x,y));
previousValue = value;
}
}
return result;
}
public static List<List<Coords>> storeValuesSorting(final int[][] labels)
{
List<Coords> sortedCoords = new ArrayList<Coords>();
for (int x = 0; x < labels.length; x++)
{
for (int y = 0; y < labels[0].length; y++)
{
sortedCoords.add(new Coords(x,y));
}
}
Collections.sort(sortedCoords, new Comparator<Coords>()
{
@Override
public int compare(Coords c0, Coords c1)
{
int v0 = labels[c0.x][c0.y];
int v1 = labels[c1.x][c1.y];
return Integer.compare(v0, v1);
}
});
List<List<Coords>> result = new ArrayList<List<Coords>>();
List<Coords> coords = null;
int previousValue = 0;
for (int i=0; i<sortedCoords.size(); i++)
{
Coords c = sortedCoords.get(i);
int value = labels[c.x][c.y];
if (i == 0 || previousValue != value)
{
coords = new ArrayList<Coords>();
result.add(coords);
}
coords.add(c);
previousValue = value;
}
return result;
}
}