【问题标题】:Find Range in which value lies in Java在Java中查找值所在的范围
【发布时间】:2013-09-28 08:01:23
【问题描述】:

假设,我有一个未排序的范围数组。 例如

class CreditRange{
   long credits;
   int id;
}

现在我要查找,给定的信用计数值属于哪个 CreditRange。

可能Set<CreditRange>的值可以是

CreditRange :{id:1,credits:0}
CreditRange :{id:2,credits:100}
CreditRange :{id:3,credits:500}
CreditRange :{id:4,credits:250}

案例 1:现在当用户输入 Credits = 50 时,这个范围比较器应该给出 回答为

CreditRange :{id:1,credits:0}

案例 2:现在当用户输入 Credits = 300 时,这个范围比较器应该给出 回答为

CreditRange :{id:4,credits:250}

案例 3:现在当用户输入 Credits = 600 时,这个范围比较器应该给出 回答为

CreditRange :{id:3,credits:500}

我们可以假设范围数组需要大约 1M 并且适合内存。我正在寻找一种简单的算法,它只使用标准 JDK 集合,没有任何 3d 方库和特殊数据结构,但运行速度相当快。

你有什么建议?

【问题讨论】:

  • 是数组还是集合?
  • 你有没有尝试过?
  • 这是一组 CreditRange
  • 我根本看不出CreditRange实际上是一个范围。它只有一个界限。如果您希望它是一个真实的范围,您需要它同时具有上限和下限。如果要保留当前结构,则应将其重命名为 CreditBound,确保将其作为 有序 集合(可能不是集合),然后使用二进制印章。

标签: java collections


【解决方案1】:

我猜,这不是你所说的范围。相反,您想要小于您传递的元素的最大元素。

您可以按照以下步骤解决问题:

  • 首先为您的班级实现Comparator,它根据学分进行比较
  • 然后,使用TreeSet,将该比较器的实例传递给它的构造函数。它会根据比较器对其中的项目进行排序。
  • 然后根据比较器使用TreeSet#floor(E) 方法得到小于E 的最大元素。当然,您必须创建一个CreditRange 的对象才能进行搜索。你不能只搜索300

演示代码:

NavigableSet<Integer> set = new TreeSet<>();
set.add(0);   set.add(100);
set.add(250); set.add(500);

System.out.println(set.floor(50));  // 0
System.out.println(set.floor(300)); // 250

请重命名你的班级。它没有以任何方式描述范围。正如 Jon Skeet 在 cmets 中指定的那样,将其命名为 CreditBound 可能会更好。

【讨论】:

  • 虽然这需要创建一个CreditRange 对象来查找值,这有点不幸:(
  • @JonSkeet。是的。我希望 Java 具有基于元素查找对象的功能。 :(这将是一个很大的解脱。
【解决方案2】:

正如 Rohit 提到的,一种简单的方法是使用 TreeSet floor(另一种是实现二进制搜索的修改变体。这是一个更完整的答案:

package test;

import java.util.TreeSet;

class CreditRange implements Comparable<CreditRange> {
  long credits;
  int id;

  public CreditRange(int id, long credits) {
    this.id = id;
    this.credits = credits;
  }

  public CreditRange(long credits) {
    this.id = -1;
    this.credits = credits;
  }

  @Override
  public int compareTo(CreditRange o) {
    return credits < o.credits ? -1 : credits > o.credits ? 1 : 0;
  }

  @Override
  public String toString() {
    return "id:" + id + ", credits:" + credits;
  }
}

public class Test {
  public static void main(String[] args) {
    TreeSet<CreditRange> set = new TreeSet<>();
    set.add(new CreditRange(1, 0));
    set.add(new CreditRange(2, 100));
    set.add(new CreditRange(3, 500));
    set.add(new CreditRange(4, 250));
    System.out.println(set.floor(new CreditRange(50)));
    System.out.println(set.floor(new CreditRange(300)));
    System.out.println(set.floor(new CreditRange(600)));
  }
}

【讨论】:

  • 当然这是一个完整的答案,但我希望 OP 弄清楚这一点。这就是为什么我没有发布代码。你给了 OP 一个简单的复制粘贴配方。
  • 好吧,当我第一次看到你的答案时,你没有演示代码和缺失部分的解释以及如何实现它们,所以我继续创建了这个(也给出了二进制搜索刺,这就是为什么花了一些时间)。既然它在这里,我认为删除它没有意义。
  • 没有问题。我当然是强迫你去做。不要以其他方式接受它。 :)
  • 感谢您的回答,但我已经使用@RohitJain 方法实现了它。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-01-01
  • 1970-01-01
  • 2011-12-19
  • 1970-01-01
  • 1970-01-01
  • 2021-08-15
相关资源
最近更新 更多