在数组

时间:2015-11-19 22:36:55

标签: java arrays algorithm

考虑以下情况:

数组amounts会跟踪一些统计数据:

int[] amounts = { 1, 2, 5, 7, 2, 4, 8, 6 };

众所周知,数组总是具有固定大小(在本例中为8)。我需要找到的是给定数量k最小元素的 索引

int   k = 5;
int[] smallest = { 1, 2, 2, 4, 5 };
int[] smallestIndices = { 0, 1, 4, 5, 2 };

我想我可以使用Selection Algorithm,但我意识到这会重新排序数组,从而返回错误的索引。

我提出的另一个想法是创建一个索引和值元组的数组,并按元组值对该数组进行排序。然后我可以提取排序数组中第一个k元组的索引。然而,这似乎是一个浪费的解决方案,可能更容易做到。

是否有算法允许我在大小为k的数组中找到n个最小数字的索引?

  • 请注意,我不是在寻找this question已经回答的最小k 数字 。我正在寻找他们的 索引 。因此,这个问题不应被标记为重复。

6 个答案:

答案 0 :(得分:3)

创建索引数组,即数组[0,n),该元素位于主数组中该索引处的元素。现在您需要做的就是从索引数组中获取顶部元素。

无需使用配对。

具体例子:

//imports
import static java.util.Comparator.comparing;

//method
public static int[] bottomN(final int[] input, final int n) {
    return IntStream.range(0, input.length)
            .boxed()
            .sorted(comparing(i -> input[i]))
            .mapToInt(i -> i)
            .limit(n)
            .toArray();
}

用法:

public static void main(String[] args) throws Exception {
    int[] amounts = {1, 2, 5, 7, 2, 4, 8, 6};
    System.out.println(Arrays.toString(bottomN(amounts, 5)));
}

输出:

 [0, 1, 4, 5, 2]

所以我们所做的就是取数组[0,1,2,3,4,5,6,8],然后按照等于当前数组元素的索引处输入数组中元素的值对其进行排序。这样就可以使用一个索引数组,按照它们在输入中的值排序。

最后,我们修剪顶部n并返回它。

答案 1 :(得分:1)

这取决于元素数量与您要查找的元素数量的比率。您将能够在O(n*log(n))中将n个元素排序为元组。但是,如果要查找的元素数量(m)为< log(n),则可以考虑简单地循环遍历列表并收集m个最小元素。然后,您将获得O(n*log(n))的复杂性。如果您想要找到一定数量的元素,那么后一种方法的复杂性将为O(n)

答案 2 :(得分:0)

您需要做的是保持元素的索引。对于你给出的例子,

int[] amounts = { 1, 2, 5, 7, 2, 4, 8, 6 }

使用数组对重新存储数组,然后得到,

pair<int,int>[] pairs = {{0, 1},{1, 2}, {2, 5}, {3, 7}, {4, 2}, {5, 4}, {6, 8}, {7, 6}}

然后将选择算法应用于对数组。请注意,您应该使用该对的第二个值作为比较一对的主键。您可以返回k个最小的值以及它们的索引。复杂性与选择算法相同。

答案 3 :(得分:0)

如果数组大小总是很小,你可以使用更简单的算法,但这对于更大的数组也应该很快。我们的想法是将索引值对放入堆中,然后取出具有最小值的k对。

public class SmallestIndicesTest {
    public static void main(String[] args) {
        // main method here as an example use case
        int[] amounts = { 1, 2, 5, 7, 2, 4, 8, 6 };
        int k = 5;
        ArrayList<Integer> smallestIndices = getNsmallestIndices(amounts, k);
        for (int i : smallestIndices) {
            System.out.println("Index i=" + i + " contains value " + amounts[i]);
        }
    }

    private static ArrayList<Integer> getNsmallestIndices(int[] t, int k) {
        ArrayList<Integer> list = new ArrayList<>();
        PriorityQueue<Pair> queue = new PriorityQueue<>();
        for (int i=0; i<t.length; i++) {
            queue.add(new Pair(t[i], i));
        }
        for (int i=0; i<k; i++) {
            Pair nextSmallest = queue.poll();
            list.add(nextSmallest.index);
        }
        return list;
    }
}


class Pair implements Comparable<Pair> {
    public int value;
    public int index;

    public Pair(int value, int index) {
        this.value = value;
        this.index = index;
    }

    @Override
    public int compareTo(Pair o) {
        return (this.value - o.value);
    }
}

答案 4 :(得分:0)

我不确定我有你的问题。 您想从数组中获取元素的多个索引吗?如果是这样,您可以尝试创建一个新数组并在那里添加索引,因此最小数组的第一个元素位于索引数组的第一个元素的索引处。 像

这样的东西
public static void main(String[] args) {
    int[] amounts = { 1, 2, 5, 7, 2, 4, 8, 6 };
    int   k = 5;
    int[] smallest = { 1, 2, 2, 4, 5 };
    int[] indexes = new int[k];
    for (int i = 0; i<k; i++) {
        int searchable = smallest[i];
        for (int j = 0; j<amounts.length; j++) {
            if (searchable == amounts[j]) {
                indexes[i] = j;
            }
        }
        }           
    for (int n = 0; n<indexes.length; n++) {
            System.out.println("Number " + smallest[n] + " index is " + indexes[n]);
    }
}

答案 5 :(得分:0)

你可以非常接近线性时间(技术上是O(nk),但基于你的描述,n很小),对于任何大小的n和k,都不需要花哨。

如果您正在处理长列表并担心缓存一致性,那么您可以创建一个包含索引和值的两个整数的对象(您可以只使用元组但对象更清晰)。创建容量n的ArrayList,最初为空。如果不担心在内存中跳转,那么只需要一个包含索引并初始化为-1的n个整数数组就足够了。只需每次都从索引中查找值。

循环遍历k的元素。对于每个元素

  • 检查该值是否低于列表中的最后一个值,如果没有移动到下一个元素,则根本不需要任何处理。
  • 如果列表长度为n,则从列表中删除最后一项,以便为新列表腾出空间。
  • 使用索引和值集创建新对象。 (仅在使用对象时才需要)
  • 扫描ArrayList,直到找到较小的对象或列表的开头
  • 在定位点插入新对象(或索引)

在通过主列表进行单次扫描结束时,ArrayList将包含最小n个值的排序列表。