【问题标题】:Retrieve multiple elements in an ArrayList that are closest to an integer检索 ArrayList 中最接近整数的多个元素
【发布时间】:2020-08-24 11:03:01
【问题描述】:

我有一个由对象组成的 ArrayList。在这些对象中,我有一个名为“级别”的字段。

我也有玩家的水平。我正在尝试检索最接近玩家级别的 ArrayList 中的元素,但前提是玩家级别高于对象中的“级别”。

例如:

        static {
        foodSources = new ArrayList<FoodSource>();
        foodSources.add(new FoodSource("foodSource1", 10));
        foodSources.add(new FoodSource("foodSource2", 10));
        foodSources.add(new FoodSource("foodSource3", 10));
        foodSources.add(new FoodSource("foodSource4", 12));
        foodSources.add(new FoodSource("foodSource5", 15));
        foodSources.add(new FoodSource("foodSource6", 15));
        foodSources.add(new FoodSource("foodSource7", 15));
        foodSources.add(new FoodSource("foodSource8", 20));
        foodSources.add(new FoodSource("foodSource9", 25));
    }

如果玩家等级为 10,它将检索 foodSource1、foodSource2 和 foodSource3。

如果玩家等级为 11,它将检索 foodSource1、foodSource2 和 foodSource3。

但是,如果玩家等级为 12,它只会检索 foodSource 4。

我正在尝试找到一种有效的方法来执行此操作。我考虑过对 ArrayList 进行二进制搜索,但据我所知,你只能用它检索一个元素。

大约一个半月前我才重新开始编程,所以我不确定我可以在这里使用 Java 中的哪些功能。

谢谢。

【问题讨论】:

    标签: java algorithm arraylist


    【解决方案1】:

    您可以创建一个Map&lt;Integer, List&lt;FoodSource&gt;&gt; levelToFoodSourceMap,在其中存储关卡与该关卡的可用食物来源之间的关系。此外,您可以编写一个方法,给定一个级别,该方法会返回最接近玩家级别的较低级别,例如

    int closestLowerLevel = findClosestLevel(12);
    List<FoodSource> foodSources = levelToFoodSourceMap.get(closestLowerLevel);
    
    

    constant time 中访问地图,findClosestLevel 可能在O(log(n)) 中实现。

    【讨论】:

    • 对,我会使用关卡作为导航地图的键——对吗?你能解释一下常数时间吗?
    • 我将一篇文章链接到时间复杂度中的常数时间。正确的是,您使用最近的级别来导航地图。但你还是要事先找到最接近的关卡。
    • TreeMap 已经能够使用 floorKey 或 ceilingKey 找到最近的。不要重新发明轮子。
    • 找到确切的数字是恒定的时间,而不是找到最接近的数字..
    • @Rubydesic 你是对的,我编辑了我的答案并支持了你的答案!
    【解决方案2】:

    您可以使用二进制搜索来查找第一个条目,然后遍历列表以查找剩余的条目。 TreeMap 对此有很好的支持,但它只从一个键(一个级别)映射到一个值,因此您必须为值使用 List。

    void append(TreeMap<Integer, List<FoodSource>> map, int level, FoodSource source) {
        map.putIfAbsent(level, new ArrayList<>());
        map.get(level).add(source);
    }
    
    TreeMap<Integer, List<FoodSource>> map = new TreeMap<>();
    append(map, 10, new FoodSource("foodSource1", 10));
    append(map, 10, new FoodSource("foodSource1", 10));
    append(map, 12, new FoodSource("foodSource1", 12));
    append(map, 15, new FoodSource("foodSource1", 15));
    
    List<FoodSource> sources = map.floorKey(12).getValue();
    

    但是,Guava 有一个 TreeMultimap 可以为您处理这些问题。唯一的问题是,它将值保存在集合中而不是列表中,因此在给定级别没有项目的排序。

    TreeMultimap<Integer, FoodSource> map = TreeMultimap.create();
    map.put(10, new FoodSource("foodSource1", 10));
    map.put(10, new FoodSource("foodSource1", 10));
    map.put(12, new FoodSource("foodSource1", 12));
    map.put(15, new FoodSource("foodSource1", 15));
    
    Set<FoodSource> sources = map.get(map.keySet().floor(12));
    

    在每种情况下,floor 表示获得小于或等于给定级别的最大键,(可以替换为ceiling 以获得大于或等于给定级别的最小键)。

    【讨论】:

      【解决方案3】:

      删除如果

      你可以使用我写的这个函数,它基于上面提到的method。 该算法首先删除级别太高的对象,然后删除级别太低的对象,最后您将拥有一个包含所需对象的新 ArrayList。


      代码

      public static ArrayList<FoodSource> find(ArrayList<FoodSource> foodSources, int level) {
          ArrayList<FoodSource> fr = new ArrayList<>(foodSources);
          // Removes objects with too high level
          fr.removeIf(n -> n.getLevel() > level);
          int max = 0;
          for (FoodSource foodSource : fr) {
              if (foodSource.getLevel() > max)
                  max = foodSource.getLevel();
          }
          int finalMax = max;
          // Removes objects with too low level
          fr.removeIf(n -> n.getLevel() < finalMax);
          return fr;
      }
      

      注意我是如何创建一个新的 ArrayList 而不修改原来的。

      【讨论】:

        【解决方案4】:

        执行此操作的正确数据结构是 TreeMap,它是二叉树。

        This answer 提供您正在寻找的信息。

        如果您不使用 TreeMap,您将不得不接受 O(n) 搜索。

        int toSearch = 11;
        int min = Integer.MAX_VALUE;
        List<FoodSource> found = new ArrayList<>();
        for (FoodSource source : foodSources) { 
            int dist = Math.abs(toSearch - source.level);
            if (dist < min) {
                min = dist;
                found.clear();
                found.add(source);
            } else if (dist == min) {
                found.add(source)
            }
        }
        

        (这也将检索 foodSource4,因为它是等距的,不确定在那种情况下你想要什么行为)

        【讨论】:

        • 在这种情况下,关键是关卡吗?
        • @MarcelDoe 就是这样。如果您不想切换数据结构,我还为您提供了 O(n) 数组列表搜索的快速算法。
        • 所以,如果我要使用树形图,我会执行以下操作: 声明一个新的树形图: TreeMap food_sources = new TreeMap( );然后添加到 TreeMap:foodsources.put(15, level10Sources);正确的?与 Hashmap 相比,这有什么好处?
        猜你喜欢
        • 1970-01-01
        • 2013-03-17
        • 1970-01-01
        • 1970-01-01
        • 2021-02-11
        • 2017-11-14
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多