Algorithm: Max Counters

后端 未结 22 2010
孤城傲影
孤城傲影 2021-02-04 07:40

I have the following problem:

You are given N counters, initially set to 0, and you have two possible operations on them:

  • increase(X) − counter X is increa
22条回答
  •  天命终不由人
    2021-02-04 08:26

    Remember:

    "Making your code readable is as important as making it executable."

    -- Robert C Martin

    Even when trying to solve a hard problem...

    So trying to achieve a better readability I've created a class to encapsulate the counters array and its operations (Law of Demeter). Sadly my first solution got only 60% in the performance test, so at the cost of a bit of readability I've improved it with a smarter solution and finally got 100%.

    Here are my two implementations with comments:

    O(N*M) Correctness 100% / Performance 60% (high redability)

    //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();
        }
    } 
    

    Codility result

    O(N+M) Correctness 100% / Performance 100% (not so high redability)

    Note the beauty of the encapsulation: to improve the algorithm I just have to edit some methods of the Counters class without changing a single character on the solution method.

    Methods edited in the Counters class:

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

    Final code:

    //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();
        }
    }
    

    Codility result

提交回复
热议问题