【问题标题】:How to find what is the rank of each element in an integer array如何查找整数数组中每个元素的排名
【发布时间】:2015-11-02 07:23:02
【问题描述】:

我想从0开始找出数组中每个元素的排名。

例如:

arr = {2, 1,3 } 
rank will be {1,0 ,2}

说明:

rank of 2 is 1 because 2 is greater than exactly 1 element
rank of 1 is 0 because 1 is greater than exactly  0  element
rank of 3 is 2 because 1 is greater than exactly  2  element

我尝试的是n^2时间复杂度算法。我想要一个线性时间复杂度的算法O(n)

有人在下面的评论部分给了我解决方案,但他的评论已被删除,我不知道如何。这适用于负整数和正整数以及非常大的列表。

感谢作者

import java.io.IOException;
import java.io.InputStream;
import java.util.*;

class rank{
    public static void main(String args[]){
        ArrayList<Integer> list = new ArrayList<Integer>();
        list.add(2);
        list.add(1);
        list.add(3);
        ArrayList<Integer> listCopy = new ArrayList<Integer>(list);

        Collections.sort(list); // sorting array
         //   System.out.println("List : " + listCopy);
         //  System.out.println("Sorted List : " + list);

        Map<Integer, Integer> rankMap = new HashMap<Integer, Integer>();
        int counter = 0;
        for(int x : list) {
            rankMap.put(x, counter); 
            // list value as key and rank as  value.
            counter++;
        }
        StringBuffer sb=new StringBuffer();
        for(int x : listCopy) {
            sb.append(rankMap.get(x) + " "); 
            // System.out.println(map.get(x));
        }
        System.out.println( sb.toString().substring(0, sb.length()-1))
    }
}

【问题讨论】:

  • 对数组进行排序呢?每个元素的索引将是它的排名。但是它可能不会在线性时间内。
  • 对数组的副本进行排序 - 删除重复项 - 将第一个数组中的 int 与具有唯一元素的排序数组中的 int 的索引进行比较
  • 计数排序会起作用吗??
  • @RealSkeptic 您是对的,只是在特殊情况下(数据类型允许)可以按线性时间排序。以基数排序为例。
  • @HyperZ 基数排序的线性是有问题的(单词的宽度以 log n 为界)。

标签: java arrays algorithm time-complexity


【解决方案1】:

所以排名是指在对数组进行排序后该元素最终的位置?

您可以从身份映射 map = {0,1,2} 开始,然后对其进行排序,但使用您的 arr 作为排序键。

Collections.sort(map, (c1, c2) -> arr[c2] > arr[c1] ? +1 : arr[c2] == arr[c1] ? 0 : -1);

这样你就不会改变你的原始数组,而是得到一个从你的数组元素到它的等级的映射。

显然,此算法取决于您的排序算法的复杂性。 您应该以 O(n log n) 结束,但也许您的数据允许使用具有 O(n) 复杂度的排序算法。但这实际上取决于您在大列表中存储的内容。

【讨论】:

  • c1c2 这里是 lambda 表达式的参数。见docs.oracle.com/javase/tutorial/java/javaOO/…
  • 如果差异足够大,arr[c2]-arr[c1] 可能会中断。
  • @Prabhu:Java 中是否有其他可用的比较运算符可用于sort
  • @Tail,如果数字太大,例如-2147483648 和 +2147483647,则答案不适合 32 位,它返回垃圾,因此失败。如果第一个小于第二个,则必须使用 if 操作返回 -1,等于 0,大于等于 1。
  • 快速手动编码版本是arr[c2] &gt; arr[c1] ? +1 : arr[c2] == arr[c1] ? 0 : -1
【解决方案2】:

首先对所有元素进行排序并存储在另一个数组中(如果元素未排序) 然后从该数组打印元素索引。

【讨论】:

  • 是否可以在 o(n) 中完成,因为 n 的大小非常大 n==1000000
  • {2, 1,3 } 排序后变成{ 1 ,2, 3} 比排名将是{ 0,1,2} 兄弟这不是我要问的应该是{1 ,0,2 }
【解决方案3】:

使用基数排序以线性时间对数组进行排序。每个元素都有自己的等级。

【讨论】:

  • {2, 1,3 } 排序后变为{ 1 ,2, 3} 而排名将是{ 0,1,2} 兄弟这不是我要问的应该是{1 ,0,2 }
【解决方案4】:

我给出一个想法。如果你愿意,你可以使用这个:

It's applicable if array value[0....n-1]
  1. 首先通过counting sort technique( 例如:array = {2, 1, 3}, 所以 count_array = { 0,1,1,1} // 这里array value 用作@ 987654325@)。
  2. 然后你可以过滤count_arrayresult_array = {0, 1, 2, 3} // 你只有add 1 with previous added value if count_array[i] == 1 (你也可以在count_array 中这样做。我使用result _array 只是为了理解)
  3. 然后你从result_array通过rank_array[i] = result_array[array[i]] - 1创建一个rank_array
  4. 终于可以通过O(n)找到你的rank_array

例子:

array = {2,1,3} 
count_array = {0,1,1,1}
result_array = {0,1,2,3}
rank_array = {1,0,2} //rank_array[i] = result_array[array[i]] - 1

【讨论】:

  • 数组可能包含负整数以及做什么
  • 通过添加一个常数值,可以使其为正。以及其他价值也增加。所以顺序不会改变
【解决方案5】:

在 java 8 中,首先要列出的数组,然后是流式传输。由于流中只有一个循环,它应该是 O(n)。

Integer[] arr = {2, 1,3 };
List <Integer> list = Arrays.asList(arr);
Integer[] outArr  = list.stream()
        .sorted()
        .map(e -> list.indexOf(e))
        .toArray(Integer[]::new);

结果:{1,0,2}

【讨论】:

  • 如果您的数组中有多个相同的条目,这将不起作用。当然,sorted() 的复杂度为 O(n log n)。
【解决方案6】:

您可以使用映射将数组中的索引映射到值,对值进行排序并返回索引。它可能看起来像这样:

private static int[] ranks(int[] array) {
  Map<Integer, Integer> m = new HashMap<> ();
  for (int i = 0; i < array.length; i++) {
    m.put(i, array[i]);
  }
  return m.entrySet().stream()
                  .sorted(Entry.comparingByValue())
                  .mapToInt(Entry::getKey)
                  .toArray();
}

示例用法:

int[] ranks = ranks(new int[] { 2, 1, 3 });
System.out.println(Arrays.toString(ranks)); //outputs {1, 0, 2}

【讨论】:

    【解决方案7】:

    可以使用称为“订单统计树”的数据结构来计算此排名,它是一种增强的数据结构。为了实现这种结构,您必须实现平衡二叉树(例如 AVL-Tree 或 Red-Black Tree),并为每个节点添加一个附加属性。这是一种非常有效的计算等级的方法,因为每个元素都需要 O(lg n)(其中 lg 是以 2 为底的对数)。您可以在第 14 章的“算法简介”中找到有关此数据结构的更多信息。

    排序的问题在于它的运行时间是 O(nlog(n)),我认为如果你想对少数元素(即少于 n 个元素)进行排名,它是低效的。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-07-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-03-07
      • 1970-01-01
      相关资源
      最近更新 更多