【问题标题】:What's wrong with this solution for Max Counters codility challengeMax Counters codility 挑战的解决方案有什么问题
【发布时间】:2013-12-28 16:48:58
【问题描述】:

所以我一直在进行关于 codility 的测试,并被“最大计数器”测试卡住了(链接 https://codility.com/demo/take-sample-test/max_counters)。我的第一个也是显而易见的解决方案如下:

def solution(N, A):

    counters = N * [0];    

    for a in A:
        if 1 <= a <= N:
            counters[a - 1] += 1;
        elif a == N + 1:
            counters = N * [max(counters)];

    return counters

这很好用,但是会花费太多时间,因为每次调用 max counters 都会填满整个数组。

所以我想出了以下解决方案,它似乎适用于小型输入,但随机地为中型和大型输入提供不正确的结果。

def solution(N, A):

    counters = N * [0];
    current_max = 0;
    last_update = 0;

    for a in A:
        if 1 <= a <= N:
            counters[a - 1] += 1;

            if counters[a - 1] < last_update:
                counters[a - 1] = last_update + 1;

            if counters[a - 1] > current_max:
                current_max = counters[a - 1];

        elif a == N + 1:
            last_update = current_max;

    for i in xrange(len(counters)):
        if counters[i] < last_update:
            counters[i] = last_update;           

    return counters

我似乎无法弄清楚它有什么问题。

编辑:结果 - http://codility.com/demo/results/demoQA7BVQ-NQT/

【问题讨论】:

  • 对你的问题没有限制,但在 python 中你不需要分号。
  • 没错。好久没用python了。
  • 最后一个循环的目的是什么?
  • 我不明白。将相同值放入所有计数器的唯一方法是 A[K]=N+1 。为什么要与最后更新计数器的每个元素进行比较?
  • 这是为了避免每次循环都必须更新整个数组,而是在循环后只更新一次,对于那些输入数组中不存在的计数器。如果你 print A, current_max, last_update 每个循环,你会看到发生了什么。

标签: python arrays algorithm


【解决方案1】:

检查这个(python,得到100分):

秘诀是不要在每次收到指令时都更新所有计数器,以将它们全部提升到新的最小值。这会导致每次操作都涉及每个计数器,并且是 ~60% 得分和 100% 得分之间的差异。

相反,通过跟踪当前最小值和最大值来避免这种命中;为您访问的每个计数器使用和更新它们。

然后,在处理完所有指令之后,因为可能有自上次 update-all 指令以来没有被自己的个人更新触及的计数器,所以自己越过计数器并确保它们处于最小值。

def solution(N, A):
    res = [0] * N
    max_val = 0
    last_update = 0
    n1 = N+1
    for i in A:
        if i < n1:
            if res[i-1] < last_update:
                res[i-1] = last_update

            res[i-1]+=1

            if res[i-1] > max_val:
                max_val = res[i-1]
        else:
            last_update = max_val

    for i in xrange(len(res)):
        if res[i] < last_update:
            res[i] = last_update

    return res

http://codility.com/demo/results/demoF3AMPT-FVN/

【讨论】:

    【解决方案2】:

    这是@jacoor 解决方案的修改版本,使用更惯用的python 和变量名称以及更接近地反映问题描述的if 语句条件。

    def fast_solution(N, A):
        counters = [0] * N
        max_counter = 0
        last_update = 0
    
        for K,X in enumerate(A): # O(M)
            if 1 <= X <= N:
                counters[X-1] = max(counters[X-1], last_update)
                counters[X-1] += 1
                max_counter = max(counters[X-1], max_counter)
            elif A[K] == (N + 1):
                last_update = max_counter
    
        for i in xrange(N): # O(N)
            counters[i] = max(counters[i], last_update)
    
        return counters
    

    https://codility.com/demo/results/demo6KPS7K-87N/

    【讨论】:

      【解决方案3】:

      这里有个问题:

      counters[a - 1] += 1
      if counters[a - 1] < last_update:
          counters[a - 1] = last_update + 1
      

      如果 counters[a - 1]last_update - 1 会怎样?

      【讨论】:

      • 当然。在else 语句之后移动第一行可以解决问题。
      【解决方案4】:

      Javascript 100/100

      function solution(N, A) {
          var max = 0,
              offset = 0,
              counters = Array.apply(null, Array(N)).map(function () {return 0;});
              
          A.forEach(function (d) {
              if (d === N + 1) {
                  offset = max;
              }
              else {
                  counters[d-1] = Math.max(offset + 1, counters[d-1] + 1);
                  max = Math.max(counters[d-1], max);
              }
          });
          
          counters.map(function (d, i) {
              if (d < offset) {
                  counters[i] = offset;
              }
          });
          
          return counters;
      }
      

      【讨论】:

        【解决方案5】:

        C# - 100/100 解决方案

        public int[] solution(int N, int[] A) {
            // write your code in C# 6.0 with .NET 4.5 (Mono)
            int[] counter = new int[N];
            int maxValue = 0;
            int minValue = 0;
            for(int i=0;i<A.Length;i++)
            {
                //less than or equal to length N
                if(A[i] <= N)
                {
                    if(counter[A[i] - 1] < minValue)
                    {
                        counter[A[i] - 1] = minValue;
                    }
                    counter[A[i] - 1] += 1;
                    if(counter[A[i] - 1] > maxValue)
                    {
                        maxValue = counter[A[i] - 1];
                    }
                }
                else if(A[i] == N+1)
                {
                    minValue = maxValue;
                }
            }
            for(int j=0;j<counter.Length;j++)
            {
                if(counter[j] < minValue)
                {
                    counter[j] = minValue;
                }
            }
            return counter;
        }
        

        【讨论】:

          【解决方案6】:

          你可以看看我的解决方案(不过是用 C# 编写的):

          public static int[] solution(int N, int[] A)
              {
                  // write your code in C# with .NET 2.0
                  var counters = new int[N];
                  var defaultValueToInitialize = 0;
                  var maxElement = 0;
          
          
                  //initializing the counters values, without increasing the N+1 actions
                  foreach (var num in A)
                  {
                      if (num == N + 1)
                      {
                          defaultValueToInitialize = maxElement;
                          counters = new int[N];
                      }
                      else
                      {
                          counters[num - 1]++;
                          if (counters[num - 1] + defaultValueToInitialize > maxElement)
                              maxElement = counters[num - 1] + defaultValueToInitialize;
                      }
          
                  }
          
                  //adding the increased default value to each cell
          
                  for (int i = 0; i < counters.Length; i++)
                  {
                      counters[i] += defaultValueToInitialize;
                  }
          
                  return counters;
              }
          

          【讨论】:

          • 感谢发帖,但“counters = new int[N];”在 foreach 循环中不是必需的吗? (编辑:哦,我明白了。这是必要的。它将计数器重置为零。)
          【解决方案7】:

          考虑一下 Ruby 中的这个 100/100 解决方案:

          # Algorithm:
          #
          # * Maintain a maximum value.
          # * For each `increase(X)` command update respective counter.
          # * For each `max_counter` command save the current max as `set_max` for later use.
          # * Once the loop is over, make an adjustment pass to set all values less than `set_max` to `set_max`.
          def solution(n, commands)
            max = set_max = 0
            counters = Array.new(n, 0)
          
            commands.each do |cmd|
              if cmd <= n
                # This is an `increase(X)` command.
                value = [counters[cmd - 1], set_max].max + 1
                counters[cmd - 1] = value
                max = [value, max].max
              else
                # This is a `max_counter` command.
                # Just update `set_max`.
                set_max = max
              end
            end
          
            # Finalize -- set counters less than `set_max` to `set_max`.
            counters.map! {|value| [value, set_max].max}
          
            # Result.
            counters
          end
          
          #--------------------------------------- Tests
          
          def test
            sets = []
            sets << ["1", [1], 1, [1]]
            sets << ["sample", [3, 2, 2, 4, 2], 5, [3, 4, 4, 6, 1, 4, 4]]
          
            sets.each do |name, expected, n, commands|
              out = solution(n, commands)
              raise "FAILURE at test #{name.inspect}: #{out.inspect} != #{expected.inspect}" if out != expected
            end
          
            puts "SUCCESS: All tests passed"
          end
          

          【讨论】:

            【解决方案8】:

            我的 python 版本只有 66 分,因为它对于后面的测试来说有点太慢了。

            def solution(N, A):
                counters = [0 for x in range(N)]
                for elem in A:
                    if elem > N:
                        cmax = max(counters)
                        counters = [cmax for x in range(N)]
                    else:
                        counters[elem-1] += 1
                return counters
            

            【讨论】:

              【解决方案9】:

              Javascript 100/100

              function solution(N, A) {
                  
                  var j, len = A.length, lastBase = 0, max = 0, 
                      counters = [], n1 = N+1;
              
                  for(j=0; j<N; j+=1){
                      counters[j]=0; //initArray
                  }
                  
                  for(j=0; j < len; j+=1){
                      if(A[j]<n1){
                          if(counters[A[j]-1] < lastBase) {
                              counters[A[j]-1] = lastBase;
                          }
                          counters[A[j]-1] += 1;
                          if(max < counters[A[j]-1]) {
                              max = counters[A[j]-1];
                          }
                      } else {
                          lastBase = max;
                      }
                  }
                  
                  for(j=0; j<N; j+=1){
                      if(counters[j] < lastBase) {
                          counters[j] = lastBase;
                      }
                  }
                  
                  return counters;
                  
              }

              【讨论】:

                【解决方案10】:

                使用 Python 的 100% 解决方案——帮助跟踪每次迭代中的最大值,而不是每次出现 N+1 时计算它

                def solution(N, A):
                    counters = [0] * N
                    all_max = list(set(A))
                    if len(all_max) == 1 and all_max[0] == N + 1:
                        return counters
                
                    the_max = 0
                    for i in A:
                        if i == N + 1:
                            counters = [the_max] * N
                        elif i > N + 1:
                            continue
                        else:
                            counters[i-1] += 1
                            if counters[i-1] > the_max:
                                the_max = counters[i-1]
                    return counters
                

                【讨论】:

                • 您的答案可以通过额外的支持信息得到改进。请edit 添加更多详细信息,例如引用或文档,以便其他人可以确认您的答案是正确的。你可以找到更多关于如何写好答案的信息in the help center
                【解决方案11】:

                C 中的 100/100 解决方案

                struct Results 
                solution(int N, int A[], int M) 
                {
                    struct Results result;
                    int *cnts = calloc(N, sizeof(int));
                    int i = 0, maxcnt = 0, j = 0, lastcnt = 0;
                    for (i = 0; i < M; i++) {
                        if (A[i] <= N && A[i] >= 1) {
                            if (cnts[A[i] - 1] < lastcnt)
                                cnts[A[i] - 1] = lastcnt + 1;
                            else
                                cnts[A[i] - 1] += 1;
                            if (cnts[A[i] - 1] > maxcnt)
                                maxcnt = cnts[A[i] - 1];
                        }
                        if (A[i] == N + 1)
                                lastcnt = maxcnt;
                    }
                    for (j = 0; j < N; j++) {
                            if (cnts[j] < lastcnt)
                                cnts[j] = lastcnt;
                    }
                    result.C = cnts;
                    result.L = N;
                    return result;
                }
                

                【讨论】:

                  【解决方案12】:

                  Java 解决方案:

                  public int[] solution(int N, int[] A) {
                      // write your code in Java SE 8
                      int[] counter = new int[N];
                      int maxCounter = 0;
                      int pos;
                      int last_max=0;
                      for (int i = 0; i < A.length; i++) {
                          if (A[i] <= N) {
                              pos = A[i];
                  
                              if (counter[pos - 1] < last_max)
                                  counter[pos - 1] = last_max;
                              counter[pos - 1] += 1;
                  
                              if (maxCounter < counter[pos - 1])
                                  maxCounter = counter[pos - 1];
                          }
                          else{
                              last_max=maxCounter;
                          }
                      }
                  
                      for (int i = 0; i < counter.length; i++) {
                          if (counter[i] < last_max)
                              counter[i] = last_max;
                      }
                      return counter;
                  }
                  

                  【讨论】:

                    【解决方案13】:

                    C 中的 MaxCounters 解决方案

                    struct Results solution(int N, int A[], int M) {
                        struct Results result;
                        // write your code in C90
                        int i,k=0,max_v=0;
                        
                        result.C =(int*)(malloc(N*sizeof(int)));
                        result.L = N;   
                        memset(result.C, 0, N*sizeof(int));  
                    
                        for(i=0;i<M;i++)
                        {      
                            if (A[i] > N)    
                                max_v=k;
                            else
                            {
                                if(result.C[A[i]-1] < max_v)
                                    result.C[A[i]-1]=max_v;
                                
                                result.C[A[i]-1]+=1; 
                                
                                if(result.C[A[i]-1] > k)
                                    k=result.C[A[i]-1];
                            }   
                        }
                    
                        for(i=0;i<N;i++)
                        {
                            if(result.C[i] < max_v)
                                result.C[i]=max_v;
                        }
                                        
                        return result;
                    }
                    

                    【讨论】:

                      【解决方案14】:

                      C++ 100/100

                      关键是忽略问题中的样本迭代,它会引导你得到一个 O(m*n) 时间复杂度的解决方案。

                      vector<int> solution(int N, vector<int> &A) {
                      // write your code in C++11
                      
                          vector<int> counters(N,0);
                          
                          int last_reset = 0, max_count = 0;
                          
                          for( unsigned int a=0; a < A.size(); ++a)
                          {
                               int current_int = A.at (a);
                               
                               if (current_int == (N+1))
                               {
                                  last_reset = max_count;
                               }
                               else
                               {
                                  unsigned int counter_index = current_int - 1;
                                   
                                  if ( counters.at (counter_index) < last_reset)
                                      counters.at (counter_index) = last_reset + 1;
                                  else
                                      ++counters.at (counter_index);
                                  if ( counters.at (counter_index) > max_count)
                                      max_count = counters.at (counter_index);
                               }
                                  
                          }
                          for( unsigned int n=0; n < counters.size(); ++n)
                          {
                              if ( counters.at (n) < last_reset)
                                  counters.at (n) = last_reset;
                          }
                          return counters;
                      
                      }
                      

                      【讨论】:

                        【解决方案15】:

                        Python 100%

                        下面的解决方案比以前的python解决方案更简单易懂,每次找到一个新的可能的时候,你可以使用set()来添加一个可能的最大数字。之后,当 A[i] 等于 N + 1 时,您使用集合中找到的最大数更新计数器并再次重置它,因为旧的最大值会更小比即将到来的和不需要的。所以我们清除集合的那一行对于通过所有性能测试非常重要

                        检测到的时间复杂度为: O(N + M)

                        def solution(N, A):
                            
                            counters = [0] * N
                            max_numbers = set()
                            
                            for i in range(0, len(A)):
                        
                                if 1 <= A[i] <= N:
                        
                                    index = A[i]-1
                                    counters[index] += 1
                                    max_numbers.add(counters[A[i]-1])
                        
                                elif A[i] == N + 1 and len(max_numbers) > 0:
                        
                                    counters = [max(max_numbers)] * N
                                    max_numbers.clear()
                        
                            return counters
                        

                        【讨论】:

                          【解决方案16】:

                          这是 Python 中最短的解决方案:

                          def solution(N, A):
                              out = [0 for _ in range(N)]
                              for ele in A:
                                  if ele<=N: out[ele-1] += 1
                                  else: out = [max(out) for i in range(len(out))]           
                              return out
                          

                          【讨论】:

                          • 每次在 out list 上调用 max() 可以降低时间复杂度。