我正在尝试将我的第一步放入Scala,练习时我看了the google code jam storecredit excersize。我首先在java中尝试过,这很顺利,现在我正在尝试将它移植到Scala。现在使用java集合框架,我可以尝试进行直接的语法转换,但我最终会在scala中编写java,这种目的无法实现。在我的Java实现中,我有一个PriorityQueue
,我将其清空为Deque
,并弹出结束,直到我们有宾果游戏。这一切都使用了可变的集合,这给我的感觉是非常'scala'。我认为更具功能性的方法是构建一个可以从最高到最低,从最低到最高遍历的数据结构。我在正确的道路上吗? Scala库中是否提供了任何合适的数据结构,或者我应该在这里自行编写?
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));
}
}
答案 0 :(得分:1)
我想知道您正在尝试使用复杂的数据结构(例如PriorityQueue
和Deque
)解决此类问题。它可以通过一对嵌套循环来解决:
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
。示例中有相当多的此类案例。然后,可以测试该条件,然后只使用indexOf
和lastIndexOf
- 除了可能只有一个 p
这样{ {1}},在这种情况下也不是答案。
所以我以更复杂的东西结束,在构建地图的同时测试补充的存在。这是完整的解决方案:
p + p == C