14

我有以下问题:

您有 N 个计数器,最初设置为 0,您可以对它们进行两种可能的操作:

  • increase(X) - 计数器 X 增加 1,
  • max_counter - 所有计数器都设置为任何计数器的最大值。

给出了一个由 M 个整数组成的非空零索引数组 A。该数组表示连续操作:

  • 如果 A[K] = X,使得 1 ≤ X ≤ N,那么操作 K 是增加(X),
  • 如果 A[K] = N + 1 则操作 K 为 max_counter。

例如,给定整数 N = 5 和数组 A 使得:

A[0] = 3
A[1] = 4
A[2] = 4
A[3] = 6
A[4] = 1
A[5] = 4
A[6] = 4

每次连续操作后计数器的值将是:

(0, 0, 1, 0, 0)
(0, 0, 1, 1, 0)
(0, 0, 1, 2, 0)
(2, 2, 2, 2, 2)
(3, 2, 2, 2, 2)
(3, 2, 2, 3, 2)
(3, 2, 2, 4, 2)

目标是在所有操作之后计算每个计数器的值。

我做了以下解决方案,但它在 O(NK) 处运行,其中 K = 数组 A 的长度。

public int[] solution(int N, int[] A) {
    int[] result = new int[N];
    int maximum = 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)
        {
            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;
        }
    }

    return result;
}

谁能告诉我如何用 O(N + K) 更好地做到这一点,其中 K 是数组 A 的长度?抱歉,编码可能很糟糕,我正在做这些练习来改进我的编程。谢谢!

4

22 回答 22

17

这是我想出的,但我不确定它是否 100% 有效:

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;
}
于 2013-09-20T04:34:50.260 回答
6

记住:

“让你的代码可读和让它可执行一样重要。”

——罗伯特·C·马丁

即使试图解决一个难题......

因此,为了获得更好的可读性,我创建了一个类来封装计数器数组及其操作(得墨忒耳法则)。遗憾的是,我的第一个解决方案在性能测试中仅获得了 60%,因此以牺牲一点可读性为代价,我使用更智能的解决方案对其进行了改进,最终获得了 100%。

这是我的两个带有注释的实现:

O(N*M) 正确性 100% / 性能 60%(高可红性)

//I didn't refactored the names of the variables N and A
//to maintain it aligned with the question description
public int[] solution(int N, int[] A)
{
    var counters = new Counters(N);

    for (int k = 0; k < A.Length; k++)
    {
        if (A[k] <= N)
            counters.IncreaseCounter(A[k]);
        else
            counters.MaxAllCounters();
    }

    return counters.ToArray();
}

public class Counters
{
    private int[] counters;
    private int greaterValueInCounter = 0;

    public Counters(int length)
    {
        counters = new int[length];
    }

    public void MaxAllCounters()
    {
        for (int i = 0; i < counters.Length; i++)
        {
            counters[i] = greaterValueInCounter;
        }
    }

    public void IncreaseCounter(int counterPosition)
    {
        //The counter is one-based, but our array is zero-based
        counterPosition--;

        //Increments the counter
        counters[counterPosition]++;

        if (counters[counterPosition] > greaterValueInCounter)
            greaterValueInCounter = counters[counterPosition];
    }

    //The counters array is encapsuled in this class so if we provide external 
    //acess to it anyone could modify it and break the purpose of the encapsulation
    //So we just exposes a copy of it :)
    public int[] ToArray()
    {
        return (int[])counters.Clone();
    }
} 

代码结果

O(N+M) 正确性 100% / 性能 100%(不那么高的可重复性)

请注意封装的美妙之处:为了改进算法,我只需要编辑Counters类的一些方法,而无需更改方法上的单个字符solution

类中编辑的方法Counters

  • IncreaseCounter()
  • MaxAllCounters()
  • ToArray()

最终代码:

//Exactly the same code
public int[] solution(int N, int[] A)
{
    var counters = new Counters(N);

    for (int k = 0; k < A.Length; k++)
    {
        if (A[k] <= N)
            counters.IncreaseCounter(A[k]);
        else
            counters.MaxAllCounters();
    }

    return counters.ToArray();
}

public class Counters
{
    private int[] counters;
    private int greaterValueInCounter = 0;
    private int currentEquilibratedScore = 0;

    public Counters(int length)
    {
        counters = new int[length];
    }

    public void MaxAllCounters()
    {
        //We don't update the entire array anymore - that was what caused the O(N*M)
        //We just save the current equilibrated score value
        currentEquilibratedScore = greaterValueInCounter;
    }

    public void IncreaseCounter(int counterPosition)
    {
        //The counter is one-based, but our array is zero-based
        counterPosition--;

        //We need to add this "if" here because with this new solution the array
        //is not always updated, so if we detect that this position is lower than
        //the currentEquilibratedScore, we update it before any operation
        if (counters[counterPosition] < currentEquilibratedScore)
            counters[counterPosition] = currentEquilibratedScore + 1;
        else
            counters[counterPosition]++;

        if (counters[counterPosition] > greaterValueInCounter)
            greaterValueInCounter = counters[counterPosition];
    }

    //The counters array is encapsuled in this class so if we provide external 
    //acess to it anyone could modify it and break the purpose of the encapsulation
    //So we just exposes a copy of it :)
    public int[] ToArray()
    {
        //Now we need to fix the unupdated values in the array
        //(the values that are less than the equilibrated score)
        for (int i = 0; i < counters.Length; i++)
        {
            if (counters[i] < currentEquilibratedScore)
                counters[i] = currentEquilibratedScore;
        }

        return (int[])counters.Clone();
    }
}

代码结果

于 2016-07-02T04:11:25.573 回答
4
def solution(N, A):
    # write your code in Python 2.6
    res = [0] * N
    m = 0
    minValue = 0
    for x in A:
        if 1 <= x <= N:
            res[x - 1] = max(res[x - 1], minValue) + 1
            if res[x - 1] > m:
                m = res[x - 1]
        else:
            minValue = m
    for i in xrange(N):
        res[i] = max(res[i], minValue)
    return res
于 2013-11-11T12:07:36.533 回答
2

这是我在 Python 中提出的一个解决方案(100/100 on codility);它与我在这里看到的其他人有点不同,所以我想我会分享:

def solution(N, A):
    count = [0] * N
    max_counter = [i for i, a in enumerate(A) if a == N+1]
    if len(max_counter) == len(A):
        return count
    if max_counter:
        mode = 0
        for i, m in enumerate(max_counter):
            if m == 0 or m - max_counter[i-1] == 1:
                continue
            subcount = {}
            if i == 0:
                for k in A[:m]:
                    if k not in subcount:
                        subcount[k] = 1
                    else:
                        subcount[k] += 1
            else:
                for k in A[max_counter[i-1]+1:m]:
                    if k not in subcount:
                        subcount[k] = 1
                    else:
                        subcount[k] += 1
            mode += max(subcount.values())
        count = [mode] * N
        for k in A[max_counter[-1]+1:]:
            count[k-1] += 1
    else:
        for k in A:
            count[k-1] += 1
    return count
于 2014-02-02T01:17:14.243 回答
1

让我们来看看...

public int[] Solution(int N, int[] A)
{
    int[] data = new int[N];
    int maxval = 0;
    int baseval = 0;
    for (int K = 0; K < A.length; K++)
    {
        int index = A[K] - 1;
        if (index < 0 || index > N)
            throw new InvalidOperationException();

        if (index < N)
            maxval = baseval + Math.Max(maxval, ++data[index]);
        else
        {
            baseval = maxval;
            data = new int[N];
        }
    }

    for (int K = 0; K < N; K++)
        data[K] += baseval;

    return data;
}

我认为是O(N+K)。取决于您如何计算重新初始化数组的顺序。

于 2013-09-20T04:56:14.710 回答
1

和每个人都得 100% 的原则一样,只是我觉得这个版本更容易阅读(可能只是因为我写的)。

using System;
using System.Linq;

class Solution 
{
    public int[] solution(int N, int[] A) 
    {

        var currentMax = 0;
        var resetValue = 0;
        var counters = Enumerable.Range(1, N).ToDictionary(i => i, i => 0);

        foreach (var a in A)
        {
            if (a == N + 1) resetValue = currentMax;
            else
            {
                counters[a] = Math.Max(counters[a], resetValue) + 1;
                currentMax = Math.Max(currentMax, counters[a]);
            }
        }
        return counters.Values.Select(v => Math.Max(v,resetValue)).ToArray();
    }
}
于 2015-06-28T17:09:46.093 回答
1

这是 PHP 中的一个实现:

function solution($N, $A) {
    $output = array_fill(0, $N, 0);
    $maxCounter = 0;
    $minCounter = 0;
    foreach ($A as $number) {
        if($number === $N + 1) {
            $minCounter = $maxCounter;
        } else if($number <= $N) {
            $number--;
            if($minCounter > $output[$number]) {
                $output[$number] = $minCounter;
            }
            $output[$number]++;
            if($output[$number] > $maxCounter) $maxCounter = $output[$number];
        }
    }

    foreach ($output as $index => $number) {
        if($number < $minCounter) $output[$index] = $minCounter;
    }

//    var_dump($output);
    return $output;
}
于 2020-10-31T23:34:04.383 回答
1

快速解决方案 100%

public func solution(_ N : Int, _ A : inout [Int]) -> [Int] {
    // write your code in Swift 4.2.1 (Linux)

    var solution = Array.init(repeating: 0, count: N)

        var max = 0
        var actualMaxValue = 0

        for obj in A {

            if (obj <= N && obj >= 1 ) {

                if solution[obj-1] < actualMaxValue {

                    solution [obj-1] = actualMaxValue + 1
                } else {

                    solution[obj-1] += 1
                }

                if (solution[obj-1] > max) {

                    max = solution[obj-1]
                }
            }
            else if obj == N+1 {

              actualMaxValue = max
            }
        }

    for (index, value) in solution.enumerated() {


        if value < actualMaxValue {

            solution[index] = actualMaxValue
        }
    }


    return solution
}
于 2020-04-19T09:54:29.740 回答
0

php中的100/100解决方案

function solution($N, $A){
    $cond     = $N + 1;
    $cur_max  = 0;
    $last_upd = 0;
    $cnt_arr  = array();
    $cnt      = count($A);
    for($i = 0; $i < $cnt; $i++){
        $cur = $A[$i];
        if($cur == $cond){
            $last_upd = $cur_max;
        }
        else{
            $pos = $cur - 1;
            if(!isset($cnt_arr[$pos])){
                $cnt_arr[$pos] = 0;
            }
            if($cnt_arr[$pos] < $last_upd){
                $cnt_arr[$pos] = $last_upd + 1;
            }
            else{
                $cnt_arr[$pos] ++;
            }
            if($cnt_arr[$pos] > $cur_max){
                $cur_max = $cnt_arr[$pos];
            }
        }
    }
    for($i = 0; $i < $N; $i++){
        if(!isset($cnt_arr[$i])){
            $cnt_arr[$i] = 0;
        }
        if($cnt_arr[$i] < $last_upd){
            $cnt_arr[$i] = $last_upd;
        }
    }
    return $cnt_arr;
}
于 2014-02-17T11:35:45.997 回答
0
public int[] counters(int N, int[] A)
{
    int[] count = new int[N];
    int maxCount = 0;
    int setAll = 0;

    for (int i = 0; i < A.Length; i++)
    {
        if (A[i] == N + 1)
        {
            setAll += maxCount;
            maxCount = 0;
            count = new int[N];
        }
        else
        {
            count[A[i] - 1] += 1;


            if (count[A[i] - 1] > maxCount)
            {
                maxCount = count[A[i] - 1];
            }
        }
    }

    for (int j = 0; j < count.Length; j++)
    {
        count[j] += setAll;
    }

    return count;
}

我认为这是 O(N+K),但 codility 说它的 O(N*K)?如果有人能解释哪个是正确的,将不胜感激......

于 2013-11-09T13:38:38.863 回答
0

Rue,我只是在本地运行这个。我自己看了柜台。我使用了这个算法:

    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
            {
                resetlimit = maximum;
                result = Enumerable.Repeat(maximum, result.Length).ToArray();
            }
        }

        //for (int i = 0; i < result.Length; i++)
        //{
        //    result[i] = Math.Max(resetlimit, result[i]);
        //}

        return result;
    }
}

查看问题和结果集,您必须在 else 语句中包含低效的 for 循环。外部的 for 循环不会复制第二个操作
•如果 A[K] = N + 1 则操作 K 是 max_counter。

为了迭代 A[3] = 6 将 result[] all 设置为 '2',您必须使用最大计数器加载结果数组。否则,您的回报将永远不会有 (2,2,2,2,2),如第 4 个示例数组所示。

我也必须通过考试才能获得我梦寐以求的工作,所以这里的低效率很重要;

该声明

  result = Enumerable.Repeat(maximum, result.Length).ToArray();

一次性加载阵列,因此没有内部循环,也没有内部效率。我认为这非常接近正确的结果集。我很惊讶他们没有要求像总回报的锯齿状阵列一样返回。尽管如此,这个代码测试还是让我很害怕。

于 2014-05-17T23:04:53.187 回答
0

红宝石 100%


def solution(n, a)
  max = 0
  offsets = a.inject(Hash.new(max)) do |acc, el|
    next Hash.new(max) if el == n+1
    acc[el] +=1
    max = acc[el] if max < acc[el]
    acc
  end
  (1..n).map{|i| offsets[i]}
end
于 2019-06-06T00:09:17.400 回答
0

爪哇,100%/100%


public int[] solution(int N, int[] A) {

int[] counters = new int[N]; int currentMax = 0; int sumOfMaxCounters = 0; boolean justDoneMaxCounter = false; for (int i = 0; i < A.length ; i++) { if (A[i] <= N) { justDoneMaxCounter = false; counters[A[i]-1]++; currentMax = currentMax < counters[A[i]-1] ? counters[A[i]-1] : currentMax; }else if (!justDoneMaxCounter){ sumOfMaxCounters += currentMax; currentMax = 0; counters = new int[N]; justDoneMaxCounter = true; } } for (int j = 0; j < counters.length; j++) { counters[j] = counters[j] + sumOfMaxCounters; } return counters; }
于 2020-03-02T09:51:36.630 回答
0

关键是 [0] * N 是一个 N 操作。如果它存在于 for 循环中,它将变为 N*M。在 Codility 中测试 100%

            # you can write to stdout for debugging purposes, e.g.
            # print "this is a debug message"

            def solution(N, A):
                # write your code in Python 2.7
                count = [0] * N
                maxCounter = 0
                minCounter = 0
                for x in A:
                    if x <= N and x >= 1:
                        count[x-1] = max(count[x-1], minCounter) + 1
                        if maxCounter < count[x-1]:
                            maxCounter = count[x-1]
                    if x == N + 1:
                        minCounter = maxCounter                
                for i in xrange(N):
                    count[i] = max(count[i], minValue)
                return count
于 2015-09-09T12:44:15.290 回答
0

C++11 代码:

#include <algorithm>

vector<int> solution(int N, vector<int> &A) {

    vector<int> hist(N, 0);

    int last_update = 0;
    int max_value = 0;

    for (auto i : A){

        if (1 <= i && i <= N){
            int& val = hist[i - 1];

            if (val < last_update)
                val = last_update + 1;
            else
                val++;

            if (max_value < val)
                max_value = val;
        }

        if (i == (N+1)){
            last_update = max_value;
        }

    }

    replace_if(hist.begin(), hist.end(), [last_update](int x){return x < last_update;}, last_update);

    return hist;
}
于 2015-07-23T05:06:25.673 回答
0

这是 Scala 版本,100% 的代码:

import java.util

def solution(N: Int, A: Array[Int]): Array[Int] = {

    var counters = new Array[Int](N)

    var maxCounter = 0

    for(ind <- 0 to A.length-1){


      if(A(ind) == (N+1)){

        //all to max
        util.Arrays.fill(counters,maxCounter)

      }else{
        //ind -1  cause array index start with 0 which is marked as 1 in the input data
        counters(A(ind)-1) += 1

        //update max counter if necessary
        if(maxCounter< (counters(A(ind)-1))) maxCounter = (counters(A(ind)-1))

      }

    }

    return counters
  }

性能:https ://codility.com/demo/results/trainingKJT6Y3-74G/

于 2015-10-26T17:06:15.450 回答
0

获得 100/100 的 Ruby Codility 代码

def solution(a)

  if a.length < 3
      0
  end
  a.sort!
  for i in 2..a.length - 1
    if (a[i-2] + a[i-1]) > a[i]
      return 1
    end
  end
 0
end
于 2016-02-08T07:17:59.370 回答
0
def solution(N, A):
    res = [0] * N
    maxV, minV = 0, 0
    for x in A:
        if 1 <= x <= N:
            res[x-1] = max(res[x-1], minV) + 1
            maxV = max(maxV, res[x-1])
        else: minV = maxV
    for i in range(N):
        res[i] = max(res[i], minV)
    return res
于 2018-10-29T05:14:49.653 回答
0

ES6

const solution = (n, a) => {
    // Initialize to zero
    let counter =  new Array(n);
    for(let i = 0  ; i < n ; i++ ){
        counter[i] = 0;
    }
    let max = 0;
    for(let j = 0  ; j < a.length ; j++ ){
        const item = a[j];
        if( item > n) {
            for(let i = 0  ; i < n ; i++ ){
                counter[i] = max;
            }
        }
        else{
            counter[item-1]++; 
            if(max < counter[item-1])
            {
                max = counter[item-1];
            }
        }
    }
    return counter;
};
于 2020-10-18T20:05:13.817 回答
0

100% JavaScript 解决方案

function solution(N, A) {
    // initialize all counters to 0
    let counters = Array(N).fill(0)

    // The maximum value of the counter is 0
    let max = 0

    // This variable will determine if an increment all operation has been encountered
    // and its value determines the maximum increment all operation encountered so far
    // for start it is 0, and we will set it to the value of max when A[i] == N + 1
    let max_all = 0

    for(let i = 0; i < A.length; i++) {

        if(A[i] <= counters.length) {

            // if the value of A[i] is 1, we have to increment c[0]
            // and hence the following index
            const c_index = A[i] - 1

            // if max all operation was found previously,
            // we have to set it here, because we are not setting anything in the else section
            // we are just setting a flag in the else section
            // if its value however is greater than max_all, it probably was already maxed
            // and later incremented, therefore we will skip it
            if(counters[c_index] < max_all) counters[c_index] = max_all

            // do the increment here
            const v = ++counters[c_index]

            // update the max if the current value is max
            max = v > max ? v : max
        }

        // this is straight forward
        else max_all = max
    }

    // if there are remaining items that have not been set to max_all inside the loop
    // we will update them here.
    // and we are updating them here instead of inside the for loop in the else section
    // to make the running time better. If updated inside the loop, we will have a running time of M * N
    // however here it's something like (M + N) ~ O(N)
    if(max_all) counters = counters.map(v => v < max_all ? max_all : v)

    // return the counters
    return counters
}
于 2020-05-27T15:27:43.990 回答
0

这是 kotlin 版本,100% 的代码

fun solutionMissingInteger(N: Int, A: IntArray): IntArray {
    val counters = IntArray(N)
    var max = 0
    var lastUpdate = 0
    for (index in A.indices) {
        val element = A[index]
        if (element == N + 1) {
            lastUpdate = max
        } else {
            val position = element - 1
            if (counters[position] < lastUpdate) {
                counters[position] = lastUpdate + 1
            } else {
                counters[position] = counters[position] +1
            }

            if (counters[position] > max) {
                max = counters[position]
            }
        }
    }
    setAllCountersToMaxValue(lastUpdate, counters)
    return counters
}

private fun setAllCountersToMaxValue(lastUpdate: Int, counters: IntArray) {
    for (index in counters.indices) {
        if (counters[index] < lastUpdate)
            counters[index] = lastUpdate
    }
}
于 2020-01-20T20:31:36.767 回答
0

我能得到的 js 最高分数是 77%

有什么改善吗?

function solution(N, A) {

  let counters = [];

  //fill counter with 0
  for (let i = 0; i < N; i += 1) {
    counters[i] = 0;
  }

  //loop array and set counters
  for (let i = 0; i < A.length; i += 1) {

    //0 index fix
    let position = A[i] - 1;

    if (A[i] <= N) {
      counters[position] += 1;
    } else {
      let max = Math.max(...counters);
      counters.fill(max)
    }

  }

  return counters;

}
于 2020-01-21T05:26:12.410 回答