【问题标题】:Java joining lists depending on values,Java 根据值加入列表,
【发布时间】:2015-04-27 08:05:14
【问题描述】:

数据: List<List<int>> startList - 填充整数列表的列表,内部列表主要有 2 个元素,如:{[1,2], [2,3],[3,1]};

任务: 需要编写将加入innerLists的算法,其中列表元素的最后一个元素等于列表的第一个元素。

例子:

  List<List<int>> startList = {[1,2],
                               [2,3],
                               [4,7],
                               [7,4],
                               [3,1],
                               [6,2],
                               [3,2],}

结果应该是:{[1,2,3,1],[1,2,3,2],[4,7,4],[6,2]}

对于我来说,我可以通过以下几个维度循环了解如何做到这一点:

while(true)
{
  ...
  for (List<String> list : startList)
  {
    ...
    for (List<String> list : startList)
    {
      ...
    }
  }
}

但这是一个非常糟糕的解决方案,因为当它是大量数据(如 5000 个 inerLists)时,它将工作数小时。 那么也许有人可以提出更好的解决方案?

【问题讨论】:

  • List&lt;int&gt; ? ...您不能在 List 中使用原语
  • 这个问题可能有多种解决方案,例如 - 你为什么不在第一次迭代中“组合”[6,2] 和 [2,3]?或者你可以只“组合”相邻的列表吗?

标签: java list join


【解决方案1】:

这似乎可以满足您的需求 - 至少它会生成您为测试输入声明的输出。我希望我正确地解释了您的需求。

我没有在last == first 停止响铃,因为这与您的预期输出不符。当它触及一个已经访问过的条目时,我已经停止了环。查看您的示例 - 您的条目 [6,2] 永远不会回到 6,因此永远不会停止。

// Finds which entry in the list is the target of the specified entry.
private int findTarget(List<List<Integer>> list, int pos) {
    // Look for that value.
    int targetValue = list.get(pos).get(1);
    for (int i = 0; i < list.size(); i++) {
        if (list.get(i).get(0) == targetValue) {
            return i;
        }
    }
    return -1;
}

private List<List<Integer>> findAllRings(List<List<Integer>> list) {
    // Maintain a BitSet to keep track of all visited nodes.
    BitSet visited = new BitSet(list.size());
    // The rings.
    List<List<Integer>> rings = new ArrayList<>();
    // Carry on until all entries have been visited.
    int start = 0;
    while (start < list.size()) {
        // Where we are in the list.
        int pos = start;
        // Grow a new ring.
        List<Integer> ring = new ArrayList<>();
        // Stop when we touch one we have already seen.
        boolean ringClosed;
        do {
            // The value to add.
            ring.add(list.get(pos).get(0));
            // Stop if it already was set.
            ringClosed = visited.get(pos);
            // Track it's visited.
            visited.set(pos);
            if (!ringClosed) {
                // Move pos.
                pos = findTarget(list, pos);
                if (pos < 0) {
                    // No next pair - break this ring.
                    ringClosed = true;
                }
            }
        } while (!ringClosed);
        // One ring!
        rings.add(ring);

        // All done - move i forward until we find an unvisited node.
        while (start < list.size() && visited.get(start)) {
            start += 1;
        }
    }
    return rings;
}

public void test() {
    List<List<Integer>> startList = new ArrayList<>(Arrays.asList(
            Arrays.asList(new Integer[]{1, 2}),
            Arrays.asList(new Integer[]{2, 3}),
            Arrays.asList(new Integer[]{3, 1}),
            Arrays.asList(new Integer[]{4, 7}),
            Arrays.asList(new Integer[]{7, 4}),
            Arrays.asList(new Integer[]{6, 2}),
            Arrays.asList(new Integer[]{6, 3}),
            Arrays.asList(new Integer[]{9, 9})
    ));
    List<List<Integer>> resultList = findAllRings(startList);
    for (List<Integer> result : resultList) {
        System.out.println(result);
    }
}

打印:

[1, 2, 3, 1]
[4, 7, 4]
[6, 2]
[6, 3]
[9, 9]

根据要求。

编辑:使用Map 来消除对内部循环的需要。我们现在应该大约是O(n)编辑: 更改了 BitSet 的用法来记录对的偏移量,而不是对的第一个条目中的值 - 阻止 BitSet 爆炸为真正的 int 值。 删除了 Map,因为它不再是优化。

【讨论】:

  • 您的代码的问题是,如果还有一个内部列表,例如 [6,3],它将忽略它,因为“6”已经存在于“已访问”集中。跨度>
  • @Edgar - 因此,您能否重申您的需求并提供更多示例来说明您的期望。目前我的代码产生了你要求的结果。
  • @Edgar - 现在怎么样?我添加了[6,3] 并确保它也能输出。
  • 现在它与 [6,3] 一起工作(例如),是否很难以这种方式更改代码,如果会有更多的 innerList [3,8] 输出将是[1,2,3,1],[1,2,3,8],...(之前的另一个输出),我在第一篇文章中更改了我的示例。
  • @Edgar - 像这样枚举所有可能的序列会更加复杂。一定要发布另一个问题,看看是否有人发布答案。
【解决方案2】:

这段代码 sn-p 在一次迭代中执行,所以顺序是 O(N)。请尝试使用您的数据集运行,如果有任何问题,请告诉我。

public class Test {
public static void main(String[] args) {
    List<List<Integer>> list = new ArrayList<List<Integer>>();
    List<Integer> one = new ArrayList<Integer>();one.add(1);one.add(2);
    List<Integer> two = new ArrayList<Integer>();two.add(2);two.add(3);
    List<Integer> three = new ArrayList<Integer>();three.add(3);three.add(1);
    List<Integer> four = new ArrayList<Integer>();four.add(4);four.add(7);
    List<Integer> five = new ArrayList<Integer>();five.add(7);five.add(4);
    List<Integer> six = new ArrayList<Integer>();six.add(6);six.add(2);
    list.add(one);list.add(two);list.add(three);list.add(four);list.add(five);list.add(six);

    System.out.println(list);

    List<List<Integer>> output = new ArrayList<List<Integer>>();

    for(int i=0;i<list.size();i++)
    {
        List<Integer> current = list.get(i);
        List<Integer> last = output.size() == 0 ? null : output.get(output.size()-1);
        if(null != last)
        {
            if(current.get(0)==last.get(last.size()-1))
            {
                last.addAll(current.subList(1, current.size()));
                output.set(output.size()-1, last);
            }
            else
            {
                output.add(current);
            }
        }
        else
        {
            output.add(current);
        }
    }

    System.out.println(output);
}
}

【讨论】:

  • 刚刚注意到错误,我没有在开始时检查 :) make : list.add(one);list.add(two);list.add(four);list.add(three) ;list.add(五);list.add(六);它会停止工作:)
  • 时间怎么样,伙计!! :) 你执行了这个并验证了吗?
  • 它对我有用!输入 == [[1, 2], [2, 3], [4, 7], [3, 1], [7, 4], [6, 2]] 输出 == [[1, 2, 3 ], [4, 7], [3, 1], [7, 4], [6, 2]] 哎呀,是不是也不能连续!!好的,我需要解决这个问题
猜你喜欢
  • 1970-01-01
  • 2023-03-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-01-07
  • 1970-01-01
  • 1970-01-01
  • 2017-11-30
相关资源
最近更新 更多