代码之家  ›  专栏  ›  技术社区  ›  john

从不同文件夹中存在的所有文件中查找100个最大数字

  •  2
  • john  · 技术社区  · 6 年前

    我最近接受了一次采访,在采访中,我被问到了下面的问题,这对我来说听起来很容易,但最后对我来说变得很棘手。

    所有文件夹及其子文件夹中都有大量文件。每个 文件的每一行都有很多数字。给定一个根文件夹,我需要找到100个最大的 所有这些文件中的数字。我提出了以下解决方案:

    • 逐行读取所有文件。
    • 将每个数字存储在数组列表中。
    • 按降序排序。
    • 现在从列表中获取前k个数字。

    我当时很困惑,不知道是否有更好/有效的方法来解决以下问题。他想让我写高效的代码。有没有更好的方法来实现这一点?

    下面是我的原始代码:

      private static final List<Integer> numbers = new ArrayList<>();
    
      public static void main(String[] args) {
        int k = 100;
        List<Integer> numbers = findKLargest("/home/david");
    
        // sort in descending order
        Collections.sort(numbers, Collections.reverseOrder());
        List<Integer> kLargest = new ArrayList<>();
        int j = 0;
        // now iterate all the numbers and get the first k numbers from the list
        for (Integer num : numbers) {
          j++;
          kLargest.add(num);
          if (j == k) {
            break;
          }
        }
        // print the first k numbers
        System.out.println(kLargest);
      }
    
      /**
       * Read all the numbers from all the files and load it in array list
       * @param rootDirectory
       * @return
       */
      private static List<Integer> findKLargest(String rootDirectory) {
        if (rootDirectory == null || rootDirectory.isEmpty()) {
          return new ArrayList<>();
        }
    
        File file = new File(rootDirectory);
        for (File entry : file.listFiles()) {
          if (entry.isDirectory()) {
            numbers.addAll(findKLargest(entry.getName()));
          } else {
            try (BufferedReader br = new BufferedReader(new FileReader(entry))) {
              String line;
              while ((line = br.readLine()) != null) {
                numbers.add(Integer.parseInt(line));
              }
            } catch (NumberFormatException | IOException e) {
              e.printStackTrace();
            }
          }
        }
        return numbers;
      }
    
    2 回复  |  直到 6 年前
        1
  •  5
  •   MBo    6 年前

    而不是存储所有 N (所有文件中数字的总计数)值并对其进行排序,您只能存储100个值—每个时刻最大的值。

    此任务的方便快捷的数据结构- priority queue binary heap ).创造

    空间复杂性是 O(K) O(NlogK) 在这里 K=100 ,因此复杂性可以评估为 O(1) O(N) (省略常数项)

    演示其工作原理的Python示例:

    import heapq, random
    
    pq = [random.randint(0, 20) for _ in range(5)]  #initial values
    print(pq)
    heapq.heapify(pq)                               #initial values ordered in heap
    print(pq)
    for i in range(5):
        r = random.randint(0, 20)    # add 5 more values
        if r > pq[0]:
            heapq.heappop(pq)
            heapq.heappush(pq, r)
        print(r, pq)
    
    [17, 22, 10, 1, 15]   //initial values
    [1, 15, 10, 22, 17]   //heapified, smallest is the left
    29 [10, 15, 17, 22, 29]     //29 replaces 1
    25 [15, 22, 17, 29, 25]     //25 replaces 10
    14 [15, 22, 17, 29, 25]      //14 is too small
    8 [15, 22, 17, 29, 25]       //8 is too small
    21 [17, 21, 25, 29, 22]     //21 is in the club now
    
        2
  •  2
  •   Naghaveer R    6 年前

    添加到@MBo中,Java实现如下所示

    使用 PriorityQueue

    使用大小为100的优先级队列创建最小堆

    int MAX = 100;
    PriorityQueue<Integer> queue = new PriorityQueue<>(MAX);
    

    从文件中读取数字,插入并平衡最小堆。将min堆中的minValue与newValue进行比较。如果较大,则删除minValue并插入newValue。

    public void balanceMinHeap(int newValue) {
    
        if(queue.size() < MAX) {
            queue.add(newValue);
            return;
        }
    
        if(queue.peek() < newValue) {
            queue.remove();
            queue.add(newValue);
        }
    
    }
    

    现在您可以从最小堆中以升序获得100个最大数

        for(int i=0;i<100;i++) {
            System.out.println(queue.remove());
        }
    

    如果您希望相同的100个最大数字按降序排列,只需将相同的队列转换为最大堆(即,再次转换为优先级队列)

    Comparator<Integer> desendingOrder = new Comparator<Integer>() {
        public int compare(Integer x, Integer y) {
             return y - x;
         }
    };
    
    PriorityQueue<Integer> maxHeap = new PriorityQueue<>(MAX, desendingOrder);
    

    或者只是在构建中使用 Collections.reverseOrder

    PriorityQueue<Integer> maxHeap = new PriorityQueue<>(MAX, Collections.reverseOrder());