MaxCounters对鳕鱼的理解

时间:2016-07-15 18:57:55

标签: c# algorithm

我想在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

来自作业的说明。

它有两个动作:

  • 增加(X) - 计数器X增加1,
  • max counter - 所有计数器都设置为any的最大值 计数器。

在条件下发生:

  • 如果A [K] = X,使得1≤X≤N,则操作K增加(X),
  • 如果A [K] = N + 1,则操作K为最大计数器。

上述代码中都说明了这两个条件。很可惜这是错的,但我很困惑,我不知道怎么能以不同的方式理解它。

为什么这段代码错了,我在任务描述中遗漏了什么?

评分最高的答案之一如下:

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代表什么?

由于我的英语,我可能完全误解了这个问题,我不确定。我只是不能过去。

编辑:

根据我提供的代码,我是如何误解作业的?一般来说,我要求解释问题。是否要解释需要做什么,或者将代码作为正确的结果并提供和解释为什么这样做?

5 个答案:

答案 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;
    }