[Hackerrank] [性能改进]相似目的地

时间:2016-07-31 14:00:45

标签: java algorithm performance

我目前正在解决我在 Hackerrank 上遇到的挑战,并且需要在代码优化/效果部门提供一些帮助。我已经设法让我的代码正常工作并返回正确的结果但是在最终测试用例中出现超时错误时失败了。输入非常大,这就解释了为什么代码需要更长的时间。

问题陈述:Similar Destinations

我试图想出修剪我的(中间)结果集的不同方法,但却找不到我还没有的东西。我相信find函数可以使用更多的调整。我已经尽力减少递归函数必须采用的路径数,但最终,它必须查看每个目标才能得出正确的结果。但是,如果目标之间共同的标记的数量低于min限制,我确实终止了一个递归路径。还有什么我可以在这里做的吗?

我的代码如下: -

  static class Destination {
    String dest;
    List<String> tags;

    public Destination(String dest, List<String> tags) {
      this.dest = dest;
      this.tags = tags;
    }

    @Override
    public String toString() {
      return dest;
    }
  }

  static List<Destination> allDest = new ArrayList<Destination>();
  static int min;
  static Set<String> keysTracker = new HashSet<String>();
  static Set<String> tagsTracker = new HashSet<String>();
  static Map<String, List<String>> keysAndTags = new HashMap<String, List<String>>();

  static void find(List<String> commonKey, List<String> commonTags, int index) {

    if (index >= allDest.size())
      return;

    if (commonTags.size() < min)
      return;

    if (tagsTracker.contains(commonTags.toString()) || keysTracker.contains(commonKey.toString())) {
      return;
    }

    String dest = allDest.get(index).dest;
    commonKey.add(dest);

    for (int i = index + 1; i < allDest.size(); ++i) {

      List<String> tempKeys = new ArrayList<String>(commonKey);
      List<String> tags = allDest.get(i).tags;
      List<String> tempTags = new ArrayList<String>(commonTags);
      tempTags.retainAll(tags);

      find(tempKeys, tempTags, i);

      if (tempTags.size() >= min) {
        if (!tagsTracker.contains(tempTags.toString())
            && !keysTracker.contains(tempKeys.toString())) {
          tagsTracker.add(tempTags.toString());
          keysTracker.add(tempKeys.toString());

          StringBuilder sb = new StringBuilder();
          for (int j = 0; j < tempKeys.size(); ++j) {
            sb.append(tempKeys.get(j));
            if (j + 1 < tempKeys.size())
              sb.append(",");
          }
          keysAndTags.put(sb.toString(), tempTags);
        }
      }
    }

  }

  public static void main(String[] args) {
    init();
    sort();
    calculate();
    answer();
  }

  static void init() {
    Scanner s = new Scanner(System.in);

    min = s.nextInt();
    s.nextLine();

    String line;
    while (s.hasNextLine()) {
      line = s.nextLine();
      if (line.isEmpty())
        break;
      String[] tokens = line.split(":");

      String dest = tokens[0];

      tokens = tokens[1].split(",");

      List<String> tags = new ArrayList<String>();
      for (int j = 0; j < tokens.length; ++j)
        tags.add(tokens[j]);
      Collections.sort(tags);

      Destination d = new Destination(dest, tags);
      allDest.add(d);
    }

    s.close();
  }

  static void sort() {
    Collections.sort(allDest, new Comparator<Destination>() {

      @Override
      public int compare(Destination d1, Destination d2) {
        return d1.dest.compareTo(d2.dest);
      }

    });
  }

  static void calculate() {
    for (int i = 0; i < allDest.size() - 1; ++i) {

      find(new ArrayList<String>(), new ArrayList<String>(allDest.get(i).tags), i);

    }
  }

  static void answer() {
    List<Map.Entry<String, List<String>>> mapInListForm = sortAnswer();

    for (Map.Entry<String, List<String>> entry : mapInListForm) {
      System.out.print(entry.getKey() + ":");
      for (int i = 0; i < entry.getValue().size(); ++i) {
        System.out.print(entry.getValue().get(i));
        if (i + 1 < entry.getValue().size())
          System.out.print(",");
      }
      System.out.println();
    }
  }

  static List<Map.Entry<String, List<String>>> sortAnswer() {
    List<Map.Entry<String, List<String>>> mapInListForm =
        new LinkedList<Map.Entry<String, List<String>>>(keysAndTags.entrySet());
    Collections.sort(mapInListForm, new Comparator<Map.Entry<String, List<String>>>() {
      public int compare(Map.Entry<String, List<String>> e1, Map.Entry<String, List<String>> e2) {

        if (e1.getValue().size() > e2.getValue().size()) {
          return -1;
        } else if (e1.getValue().size() < e2.getValue().size()) {
          return 1;
        }
        return e1.getKey().compareTo(e2.getKey());

      }
    });
    return mapInListForm;
  }

非常感谢任何帮助。谢谢!

1 个答案:

答案 0 :(得分:0)

经过一些选择性分析后,我设法解决了这个问题。看起来我最初的预感是正确的。这个问题与算法关系不大,更多的是我正在使用的数据结构!罪魁祸首是find方法。具体来说,在两个retainAll上调用lists方法时。我忘记了需要花费O(n ^ 2)的时间来迭代两个lists。这就是为什么它很慢。然后,我将list更改为HashSet。正如我们大多数人所知,HashSet在访问其值时具有O(1)时间复杂度。 retainAll方法保留但不是找到两个lists之间的交集,而是找到两个sets之间的交集!这成功地减少了总运行时间和所有测试通过的几秒钟。 :)

find方法现在看起来像这样: -

  static void find(List<String> commonKey, List<String> commonTags, int index) {

    if (index >= allDest.size())
      return;

    if (commonTags.size() < min)
      return;

    if (tagsTracker.contains(commonTags.toString()) || keysTracker.contains(commonKey.toString())) {
      return;
    }

    String dest = allDest.get(index).dest;
    commonKey.add(dest);

    for (int i = index + 1; i < allDest.size(); ++i) {

      List<String> tempKeys = new ArrayList<String>(commonKey);
      List<String> tags = allDest.get(i).tags;
      Set<String> tempTagsSet1 = new HashSet<String>(commonTags);
      Set<String> tempTagsSet2 = new HashSet<String>(tags);
      tempTagsSet1.retainAll(tempTagsSet2);
      List<String> tempTags = new ArrayList<String>(tempTagsSet1);

      if (tempTags.size() >= min)
        Collections.sort(tempTags);

      find(tempKeys, tempTags, i);

      if (tempTags.size() >= min) {
        if (!tagsTracker.contains(tempTags.toString())
            && !keysTracker.contains(tempKeys.toString())) {
          tagsTracker.add(tempTags.toString());
          keysTracker.add(tempKeys.toString());

          StringBuilder sb = new StringBuilder();
          for (int j = 0; j < tempKeys.size(); ++j) {
            sb.append(tempKeys.get(j));
            if (j + 1 < tempKeys.size())
              sb.append(",");
          }
          keysAndTags.put(sb.toString(), tempTags);
        }
      }
    }

 }