【问题标题】:get indexes of n smallest elements in an array获取数组中 n 个最小元素的索引
【发布时间】:2011-02-16 13:45:20
【问题描述】:

我有一个 int 数组 int[] myArray = new int[100]; 并且想要获取最小 10(任意 n)个元素的索引。我该怎么做?

【问题讨论】:

  • 如果您展示了您的尝试,这将有助于社区提供更好的帮助。具体来说,如果您正在尝试某些代码并且它运行不正常,最好向我们展示似乎无法正常运行的 sn-p。
  • @erasmus 他在问这是否用于家庭作业。标记为作业的问题会收到不同的答案。例如 How do I sort an array with [homework] tag 将导致对不同排序算法的解释,没有它,将得到Arrays.sort( list );
  • @Oscar,我不认为他是真诚的。像他这样的人也有。他们所做的是降低问题的投票值并编写一些挑衅性的 cmets。那些家伙只是没用的东西。
  • @erasmus:有时问题以不清楚的方式发布。我不得不读了好几遍,因为我不太明白。我添加了我的答案,看看是不是你需要的。
  • @erasmus:我必须同意 Oscar 的观点——这个问题在我看来是一个家庭作业式的问题。

标签: java


【解决方案1】:

排序数组然后选择 10 很简单,但它会是 O(n log n),如果你不想重新排序初始数组,你也需要复制一份。

一个更好的主意是使用最大堆(或优先级队列),它会在您插入元素时自动对元素进行排序,这样最大的元素就是根节点。沿着数组走,继续放入元素,直到达到 10;然后,对于每个后续元素,只需检查它是否小于堆中最大的元素(恒定时间检查),如果是,则将其弹出并插入新元素。当你遍历整个数组时,里面剩下的 10 个东西就是你的最小元素。这会让你得到 O(n log 10) == O(n) 的结果,因为每次插入堆只花费 O(log 10)。

Java 的 Priority Queue 实现默认是最小队列,因此您需要传入一个反转排序的 Comparator。有关如何执行此操作的示例,请参阅this question。如果您想在最后获取索引,您还需要创建一个包含 (value, index) 对的自定义对象。

【讨论】:

    【解决方案2】:

    创建一个包含数字和索引的对象,然后创建这些对象的数组,然后执行 Array.Sort(arrayset[],comparator)java docs。然后你就可以从排序后的数组中挑选出前 x 项。

    编辑: 像这样的东西...... [我用这个根据'距离'进行排序

    import java.util.Arrays;
    import java.util.Comparator;
    
    public class NearestObject
    {
        public NearestObject(int position, int distance)
        {
             this.Position = position;
             this.Distance = distance;
        }
        public int Position = 0;
        public int Distance = 0;
    
        public static NearestObject[] SortDistance(NearestObject[] items)
        {
            Arrays.sort(items, new DistanceSort());
            return items;
        }
    
    }
    
    class DistanceSort implements Comparator<NearestObject>
    {
        public int compare(NearestObject o1, NearestObject o2)
        {
            return o1.Distance - o2.Distance;
        }
    }
    

    【讨论】:

      【解决方案3】:

      直接的解决方案是遍历数组并维护您找到的 n 个最小元素及其索引的列表。这是一个 O(N) 的解决方案,在大多数情况下都可以接受。我猜这是家庭作业,你必须有比 O(N) 更好的东西。

      【讨论】:

      • 不是 O(n*m) 吗? (n=输入大小,m=项目数)
      • @Kurru,诚然,我的回答的细节并不完全清楚。我认为这个问题以前被标记为作业。我不认为它是 O(NM) 因为不必遍历 M 元素的列表。一旦找到第 M 个最小的元素,N 列表上的所有后续迭代只需要根据第 M 个元素检查自己。我认为最好通过使用优先级堆来促进这种行为。所以... O(Nlog(M)) ???
      • 所以我想我的答案只是@tzaman 答案的描述性较差的版本。
      • 优先级循环是否在最坏的情况下插入和读取日志(M)?不知道
      • 在读取堆时,通常会关注最小值或最大值,实现通常允许 O(1) 的读取复杂度。插入/删除复杂度为 O(logN)。这是 Java 的 PriorityQueue:download.oracle.com/javase/6/docs/api/java/util/… 该类的 javadoc 的最后一行描述了当前实现所保证的时间复杂度。
      【解决方案4】:

      按索引排序并返回前 10 个

      首先创建一个结构来保存索引和值:

      class IndexValue {
         final int i;
         final int v;
      }
      

      然后用这个新结构创建一个数组:

      IndexValue[] array = new IndexValue[myArray.length];
      for( int i = 0 ; i < array.length ; i++ ) {
          array[i] = new IndexValue( i, myArray[i] );
      }
      

      最后排序,取前N个元素

      Arrays.sort( array ); // you'll need to implement Comparator though 
      
      for( int i = 0 ; i< 10 ;i++ ) {
          System.out.print( array[i] );
      }
      

      这是完整的工作代码:

      import java.util.Arrays;
      import java.util.Random;
      import java.util.Comparator;
      import static java.lang.System.out;
      
      class IndexValue {
         final int i,v;
      
         public IndexValue( int i, int v ) {
             this.i = i;
             this.v = v;
         }
      }
      public class SortByIndex {
          public static void main( String [] args ) {
      
              Random random = new Random();
      
              int [] myArray = new int[100];
              IndexValue[] array = new IndexValue[myArray.length];
      
              // Fill the array 
              for( int i = 0 ; i < 100; i++ ) {
                  myArray[i] = random.nextInt();
                  array[i] = new IndexValue( i, myArray[i] );
              }
      
              // Sort it 
              Arrays.sort( array, new Comparator<IndexValue>(){
                  public int compare( IndexValue a, IndexValue b ){
                      return a.v - b.v;
                  }
              });
      
              // Print it
              out.println("Top:");
              for( int i = 0 ; i < 10 ; i++ ) {
                  out.println( String.format("array[%d]=%d",  array[i].i, array[i].v ));
              }
      
          }
      }
      

      【讨论】:

        【解决方案5】:

        您可以对数组进行排序,循环前 10 个元素,然后为每个元素在数组中搜索它所在的位置...也许这不是更有效的方法,但它更容易。

        【讨论】:

          【解决方案6】:

          如果您正在寻找一个实用的答案(相对于实际的排序算法等),那么只需使用 HashMap 或 PriorityQueue。如果速度不是问题,试试这个简单的算法。它比 PriorityQueue 更容易,因为您不需要自定义对象:

          HashMap&lt;Integer, ArrayList&lt;Integer&gt;&gt; indexMap = new HashMap&lt;Integer, ArrayList&lt;Integer&gt;&gt;();

          填写 indexMap 以便我们可以获取数组中任何给定数字的索引

          for (int index = 0; index <= array.size; index++) {
             if (indexMap.get(array[index]) == null) { // Prime it with an ArrayList
                indexMap.put(array[index], new ArrayList<Integer>());
             }
          
             indexMap.get(array[index]).add(index);
          }
          

          对于数组中最小的 n 个数,打印出它们的索引。

          Arrays.sort(array);
          for (int index = 0; index <= n; index++) {
             System.out.println(indexMap.get(array[index]).remove(0));
          }
          

          【讨论】:

            猜你喜欢
            • 2023-03-13
            • 2011-02-11
            • 1970-01-01
            • 2021-12-25
            • 2011-04-13
            • 1970-01-01
            • 2020-08-09
            • 2013-07-11
            • 1970-01-01
            相关资源
            最近更新 更多