【问题标题】:Java 8 : How to find kth smallest, efficientlyJava 8:如何有效地找到第 k 个最小的
【发布时间】:2017-06-26 03:02:40
【问题描述】:

在 java 8 中如何有效地找到第 K 个最小的?第 K 个最小的是

http://www.geeksforgeeks.org/kth-smallestlargest-element-unsorted-array/

我在下面尝试过。如果有一个更有效的解决方案可以提供 Java-8 的安全性,例如我不应该在访问索引之前检查大小以防空数组等。我相信我自己的解决方案是安全的空数组。

如果存在我的 Java-8 方法和更好的 Java-8 方法的可证明的时间复杂度比较,我们将不胜感激。谢谢。

package lab.rat.jerry.kthsmallest;

import static java.util.stream.Collectors.toList;

import java.util.Arrays;
import java.util.List;

public class KthSmallest {

    // Inputs
    static int k = 3;

    static Integer[] myIntArray = {2, 3, 1, 4, -2, 0, -3, 0, -1, 5 };

    public static void main(String[] args) {

        List<Integer> list = Arrays.asList(myIntArray);

        System.out.println(list
            .stream()
            .sorted()
            .distinct()
            .limit(k)
            .skip(k-1)
            .collect(toList())
            );
    }
}

【问题讨论】:

  • 您正在对输入进行排序,这意味着您的运行时间为 O(nlog(n))。如果我没记错的话,找到第 k 个最小(或最大)元素的最佳算法需要 O(n) 时间。该算法类似于快速排序,但运行速度更快,因为它不必对整个输入进行排序。
  • 我不确定关于时间复杂度分析的问题是否适合本网站。最好去cs或者codereview子站
  • 为什么要将单个元素收集到List
  • 这是一个算法问题,所以应该在cs上问。
  • @Eran 的意思是quickselect。关于实际问题,没有 java-8 特定 改进。 Peter Lawrey 提到的基于TreeSet 的解决方案更容易实现,并且仍然比基于流的方法更好。但与 quickSelect 一样,它仍然不是 Java 8 特定的。

标签: java java-8 java-stream comparator


【解决方案1】:

你可以试试这个:

package lab.rat.jerry.kthsmallest;

import java.util.Arrays;
import java.util.List;

public class KthSmallest {

       // Inputs
      static int k = 3;

      static Integer[] myIntArray = {2, 3, 1, 4, -2, 0, -3, 0, -1, 5 };

      public static void main(String[] args) {

         List<Integer> list = Arrays.asList(myIntArray);

         int smallest = list.stream()
                            .mapToInt(Integer::intValue)
                            .sorted()
                            .limit(k)
                            .skip(k-1)
                            .findFist()
                            .getAsInt();
         System.out.println(smallest);
     }
}

通过使用这种方法,您可以避免 NullPointerException。因为findFist() 将返回可选的。

希望对你有帮助:)

【讨论】:

  • 请注意,它没有使用 distinct(尽管它并不重要)。请注意,我自己的代码对空数组也是安全的。请注意,时间复杂度相关信息不在答案中。你能分享更多细节吗?
  • 问题中已经包含的代码没有真正的区别。由于问题的代码已经选择了一个元素,所以附加一个min() 操作没有任何意义,一个简单的findFirst() 也可以。或者只是forEach(System.out::println)
【解决方案2】:

您可以在 Java 中使用简单的数据结构 PrioretyQueue。您可以快速获取和删除最大或最小元素:

public static int kthLargestElement(int[] nums, int k) {

    PriorityQueue<Integer> queue = new PriorityQueue<>();
    for (int i = 0; i < nums.length ; i++) {
        queue.add(nums[i]);
    }
    while (k > 1){
        queue.poll();
        k-=1;
    }
    return queue.poll();
}

【讨论】:

  • You 方法根据位置返回元素。重复元素呢?
  • 此方法在未排序的数组中找到第 k 个最大的元素。这将是排序顺序中第 k 个最大的元素,而不是第 k 个不同的元素。
  • 我明白这一点。但是 OP 在他们的代码中使用了 distinct,所以我认为重复是值得关注的。但我可能是错的。
  • 是的,它也适用于重复项。在我的情况下(来自 codesignal.com 的问题,以查找 KTh 更大的元素)它有效地工作。
【解决方案3】:

我不知道这有多有效,但考虑到以下情况:

  1. 数组包含重复值。
  2. k 大于最终列表。
      int k = 4;
      int[] numbs = { 1, 2, 3, 3, 3, 3, 3, 3,10,11,12
      };

      int smallest =
            Arrays.stream(numbs).distinct().sorted().skip(k - 1).limit(
                  1).findFirst().orElse(Integer.MIN_VALUE);

      System.out.println(smallest);
  1. 这会将数组转换为流。
  2. 删除重复项
  3. 对剩下的进行排序。
  4. 跳过前 k-1 个值。
  5. 将列表的其余部分限制为一个
  6. 退货。

如果 k 太大,则返回最小 int 值。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-10-22
    • 2018-11-18
    • 2023-03-11
    • 2015-01-15
    • 2021-01-06
    • 1970-01-01
    • 2020-12-24
    • 1970-01-01
    相关资源
    最近更新 更多