【发布时间】:2020-01-17 12:18:10
【问题描述】:
我在 Codility 编码挑战中遇到了很多困难:https://app.codility.com/programmers/challenges/chromium2017/
(基本问题是:给定一个整数列表,计算可能的升序数在i 的同一侧。例如,给定 [6, 2, 3, 4],从 2 开始,我们可以去 [2], [2, 3], [2, 4], [2, 6 ]、[2、3、6] 或 [2、4、6]。)
到目前为止,我只能考虑时间复杂度为 O(N^2) 而需要 O(N*log(N)) 的解决方案。尽管有人在 GitHub 上发布了解决方案,但我不知道发生了什么:
https://github.com/kalwar/Codility/blob/master/chromimum2017_solution.c
他似乎在来回进行仿射变换,但我缺乏对为什么这样做有效以及为什么可以用 O(N*Log(N)) 时间复杂度实现它的洞察力。我希望有人能解释一下。
我在下面发布了自己的解决方案(用 Java 编写):
final class Chromium {
final long MODULUS = 1000000007L;
static class Nest implements Comparable<Nest> {
Nest(int index, int height) {
this.index = index;
this.height = height;
}
int index;
int height;
public int compareTo(Nest nest2) {
return Integer.compare(height, nest2.height);
}
}
/**
* Calculates the possibilities based on the fact that it is a multiplication of the runs of consecutive nests
* left and right of the nest in focus.
*/
private long getPossibleWays(Nest[] orderedNests, int startIndex) {
Nest startNest = orderedNests[startIndex];
long ways = 0;
long oppositeNumberOfWays = 0;
boolean previousLeft = false;
boolean first = true;
int runLength = 0;
for (int i = orderedNests.length - 1; i > startIndex; --i) {
Nest n = orderedNests[i];
boolean left = n.index < startNest.index;
if (left != previousLeft && !first) {
ways += (runLength * (oppositeNumberOfWays + 1)) % MODULUS;
long w = oppositeNumberOfWays;
oppositeNumberOfWays = ways;
ways = w;
runLength = 1;
} else {
runLength++;
}
first = false;
previousLeft = left;
}
ways += (runLength * (oppositeNumberOfWays + 1)) % MODULUS;
return 1 + ways + oppositeNumberOfWays;
}
public int solution(int[] H) {
Nest[] nests = new Nest[H.length];
for (int i = 0; i < H.length; ++i) {
nests[i] = new Nest(i, H[i]);
}
// Sort the nests by height
Arrays.sort(nests);
long possibleWays = 0;
for (int i = 0; i < nests.length; ++i) {
possibleWays += getPossibleWays(nests, i);
possibleWays = possibleWays % MODULUS;
}
return (int) possibleWays;
}
}
【问题讨论】: