我想在Codility上尝试一些挑战并从头开始。所有作业都相对容易,直到名为MaxCounters的作业。我不相信这一点特别难,虽然它是第一个标记为不是无痛的。
我已阅读task并开始使用C#语言进行编码:
public static int[] maxPart(int N, int[] A){
int[] counters = new int[N];
for(int i = 0; i < A.Length; i++){
for(int j = 0; j < counters.Length; j++){
if(A[i] == counters[j] && (counters[j] >= 1 && counters[j] <= N )){
counters [j] = counters [j] + 1;
}
if(A[i] == N + 1 ){
int tmpMax = counters.Max ();
for(int h = 0; h < counters.Length; h++){
counters [h] = tmpMax;
}
}
}
}
return counters;
}
当然有3个循环会让它变得非常慢,但是让它留待以后再使用。我关心的是我是如何理解这一点的,所有其他人在这个问题上都看到了here。
来自作业的说明。
它有两个动作:
在条件下发生:
上述代码中都说明了这两个条件。很可惜这是错的,但我很困惑,我不知道怎么能以不同的方式理解它。
为什么这段代码错了,我在任务描述中遗漏了什么?
评分最高的答案之一如下:
public int[] solution(int N, int[] A) {
int[] result = new int[N];
int maximum = 0;
int resetLimit = 0;
for (int K = 0; K < A.Length; K++)
{
if (A[K] < 1 || A[K] > N + 1)
throw new InvalidOperationException();
if (A[K] >= 1 && A[K] <= N)
{
if (result[A[K] - 1] < resetLimit) {
result[A[K] - 1] = resetLimit + 1;
} else {
result[A[K] - 1]++;
}
if (result[A[K] - 1] > maximum)
{
maximum = result[A[K] - 1];
}
}
else
{
// inefficiency here
//for (int i = 0; i < result.Length; i++)
// result[i] = maximum;
resetLimit = maximum;
}
}
for (int i = 0; i < result.Length; i++)
result[i] = Math.max(resetLimit, result[i]);
return result;
}
此代码以100%的Codility结果。
问题:
我想知道作者如何知道使用result[A[K] - 1]
的任务? resetLimit
代表什么?
由于我的英语,我可能完全误解了这个问题,我不确定。我只是不能过去。
编辑:
根据我提供的代码,我是如何误解作业的?一般来说,我要求解释问题。是否要解释需要做什么,或者将代码作为正确的结果并提供和解释为什么这样做?
答案 0 :(得分:2)
在我看来,你以某种方式混合了计数器的索引(A
中的值)和计数器的值(counter
中的值)。所以使用A[i]-1
没有任何魔力 - 它是问题描述中的值X
(调整为基于0的索引)。
我天真的方法是,我理解问题的方式(我希望它能说清楚,你的代码做错了什么):
public static int[] maxPart(int N, int[] A){
int[] counters = new int[N];
for(int i = 0; i < A.Length; i++){
int X=A[i];
if(X>=1 && X<=N){ // this encodes increment(X), with X=A[i]
counters [X-1] = counters [X-1] + 1; //-1, because our index is 0-based
}
if(X == N + 1 ){// this encodes setting all counters to the max value
int tmpMax = counters.Max ();
for(int h = 0; h < counters.Length; h++){
counters [h] = tmpMax;
}
}
}
}
return counters;
}
显然,在下列操作序列的情况下,复杂性为O(n^2)
且n=10^5
个操作数(数组A
的长度),这将太慢; < / p>
max counter, max counter, max counter, ....
最高级别的解决方案以惰性方式解决问题,并且每次遇到max counter
操作时都不会显式更新所有值,而只是记住{{1}中此操作后所有计数器必须具有的最小值}}。因此,每当他必须增加一个计数器时,他会查看是否必须根据以前的resetLimit
操作更新其值,并补偿他未在此计数器上执行的所有max counter
操作
max counter
他的解决方案在if(result[A[K] - 1] < resetLimit) {
result[A[K] - 1] = resetLimit + 1;
}
中运行并且足够快。
答案 1 :(得分:1)
这是我的JavaScript解决方案。
const maxCounters = (N, A) => {
for (let t = 0; t < A.length; t++) {
if (A[t] < 1 || A[t] > N + 1) {
throw new Error('Invalid input array A');
}
}
let lastMaxCounter = 0; // save the last max counter is applied to all counters
let counters = []; // counters result
// init values by 0
for (let i = 0; i < N; i++) {
counters[i] = 0;
}
let currentMaxCounter = 0; // save the current max counter each time any counter is increased
let maxApplied = false;
for (let j = 0; j < A.length; j++) {
const val = A[j];
if (1 <= val && val <= N) {
if (maxApplied && counters[val - 1] < lastMaxCounter) {
counters[val - 1] = lastMaxCounter;
}
counters[val - 1] = counters[val - 1] + 1;
if (currentMaxCounter < counters[val - 1]) {
currentMaxCounter = counters[val - 1];
}
} else if (val === N + 1) {
maxApplied = true;
lastMaxCounter = currentMaxCounter;
}
}
// apply the lastMaxCounter to all counters
for (let k = 0; k < counters.length; k++) {
counters[k] = counters[k] < lastMaxCounter ? lastMaxCounter : counters[k];
}
return counters;
};
答案 2 :(得分:0)
这是一个非常优雅的 Swift 解决方案:
public func solution(_ N : Int, _ A : inout [Int]) -> [Int] {
var globalMax = 0
var currentMax = 0
var maximums: [Int: Int] = [:]
for x in A {
if x > N {
globalMax = currentMax
continue
}
let newValue = max(maximums[x] ?? globalMax, globalMax) + 1
currentMax = max(newValue, currentMax)
maximums[x] = newValue
}
var result: [Int] = []
for i in 1...N {
result.append(max(maximums[i] ?? globalMax, globalMax))
}
return result
}
答案 3 :(得分:0)
试试这个 Java 片段。它更具可读性和更整洁,您无需担心边界检查,并且可能会撤消与您发现的更有效方法相关的第一个发现,顺便说一句,最大值位于主 forloop 上,不会造成任何开销。
public final int[] solution(int N, int[] A)
{
int condition = N + 1;
int currentMax = 0;
int lastUpdate = 0;
int[] counters = new int[N];
for (int i = 0; i < A.length; i++)
{
int currentValue = A[i];
if (currentValue == condition)
{
lastUpdate = currentMax;
}
else
{
int position = currentValue - 1;
if (counters[position] < lastUpdate)
{
counters[position] = lastUpdate + 1;
}
else
{
counters[position]++;
}
if (counters[position] > currentMax)
{
currentMax = counters[position];
}
}
}
for (int i = 0; i < N; i++)
{
if (counters[i] < lastUpdate)
{
counters[i] = lastUpdate;
}
}
return counters;
}
答案 4 :(得分:0)
这是 C# 解决方案,给我 100% 的分数
public int[] solution(int N, int[] A) {
int[] operation = new int[N];
int max = 0, globalMax = 0;
foreach (var item in A)
{
if (item > N)
{
globalMax = max;
}
else
{
if (operation[item - 1] < globalMax)
{
operation[item - 1] = globalMax;
}
operation[item - 1]++;
if (max < operation[item - 1])
{
max = operation[item - 1];
}
}
}
for (int i = 0; i < operation.Length; i++)
{
if (operation[i] < globalMax)
{
operation[i] = globalMax;
}
}
return operation;
}