scala中的搜索树

时间:2011-06-02 10:51:01

标签: sorting scala collections traversal

我正在尝试将我的第一步放入Scala,练习时我看了the google code jam storecredit excersize。我首先在java中尝试过,这很顺利,现在我正在尝试将它移植到Scala。现在使用java集合框架,我可以尝试进行直接的语法转换,但我最终会在scala中编写java,这种目的无法实现。在我的Java实现中,我有一个PriorityQueue,我将其清空为Deque,并弹出结束,直到我们有宾果游戏。这一切都使用了可变的集合,这给我的感觉是非常'scala'。我认为更具功能性的方法是构建一个可以从最高到最低,从最低到最高遍历的数据结构。我在正确的道路上吗? Scala库中是否提供了任何合适的数据结构,或者我应该在这里自行编写?

编辑:Java中更简单版本的完整代码。它应该在O(max(credit,inputchars))中运行并且已成为:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;

public class StoreCredit {
    private static BufferedReader in;

    public static void main(String[] args) {
        in = new BufferedReader(new InputStreamReader(System.in));
        try {
            int numCases = Integer.parseInt(in.readLine());
            for (int i = 0; i < numCases; i++) {
                solveCase(i);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    private static void solveCase(int casenum) throws NumberFormatException,
            IOException {
        int credit = Integer.parseInt(in.readLine());
        int numItems = Integer.parseInt(in.readLine());
        int itemnumber = 0;
        int[] item_numbers_by_price = new int[credit];
        Arrays.fill(item_numbers_by_price, -1); // makes this O(max(credit,
                                                // items)) instead of O(items)
        int[] read_prices = readItems();
        while (itemnumber < numItems) {
            int next_price = read_prices[itemnumber];
            if (next_price <= credit) {
                if (item_numbers_by_price[credit - next_price] >= 0) {
                    // Bingo! DinoDNA!
                    printResult(new int[] {
                            item_numbers_by_price[credit - next_price],
                            itemnumber }, casenum);
                    break;
                }
                item_numbers_by_price[next_price] = itemnumber;
            }
            itemnumber++;
        }
    }

    private static int[] readItems() throws IOException {
        String line = in.readLine();
        String[] items = line.split(" "); // uh-oh, now it's O(max(credit,
                                          // inputchars))
        int[] result = new int[items.length];
        for (int i = 0; i < items.length; i++) {
            result[i] = Integer.parseInt(items[i]);
        }
        return result;
    }

    private static void printResult(int[] result, int casenum) {
        int one;
        int two;
        if (result[0] > result[1]) {
            one = result[1];
            two = result[0];
        } else {
            one = result[0];
            two = result[1];
        }
        one++;
        two++;
        System.out.println(String.format("Case #%d: %d %d", casenum + 1, one,
                two));
    }

}

1 个答案:

答案 0 :(得分:1)

我想知道您正在尝试使用复杂的数据结构(例如PriorityQueueDeque)解决此类问题。它可以通过一对嵌套循环来解决:

for {
  i <- 2 to I
  j <- 1 until i
  if i != j && P(i-1) + P(j - 1) == C
} println("Case #%d: %d %d" format (n, j, i))

比线性更糟,比二次更好。由于这些项目没有排序,并且排序它们需要O(nlogn),因此我无法做到这一点 - 就我所见。

实际上,说了这么多,我现在已经找到了一种在线性时间内完成它的方法。诀窍在于,对于您找到的每个数字p,您都知道它的补充是什么:C - p。我希望有几种方法可以探索 - 我到目前为止已经想过两个。

一种方法是构建具有O(n)特征的地图,例如位图或哈希图。对于每个元素,使其指向其索引。然后只需要找到一个元素,其补码也在地图中有一个条目。琐碎的是,这可能就像这样容易:

val PM = P.zipWithIndex.toMap
val (p, i) = PM find { case (p, i) => PM isDefinedAt C - p }
val j = PM(C - p)

但是,如果数字等于其补码,则无效。换句话说,如果有两个p,那么p + p == C。示例中有相当多的此类案例。然后,可以测试该条件,然后只使用indexOflastIndexOf - 除了可能只有一个 p这样{ {1}},在这种情况下也不是答案。

所以我以更复杂的东西结束,在构建地图的同时测试补充的存在。这是完整的解决方案:

p + p == C