【问题标题】:count distinct slices in an array计算数组中的不同切片
【发布时间】:2017-04-12 09:09:33
【问题描述】:

我试图解决this 问题。

一个整数 M 和一个由 N 组成的非空零索引数组 A 给出了非负整数。数组 A 中的所有整数都小于 或等于 M。

一对整数 (P, Q),使得 0 ≤ P ≤ Q

例如,考虑整数 M = 6 和数组 A,这样:

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

正好有九个不同的切片:(0, 0), (0, 1), (0, 2), (1, 1), (1,2), (2, 2), (3, 3), (3, 4) 和 (4, 4)。

目标是计算不同切片的数量。

提前致谢。

#include <algorithm>
#include <cstring>
#include <cmath>
#define MAX 100002

// you can write to stdout for debugging purposes, e.g.
// cout << "this is a debug message" << endl;

using namespace std;

bool check[MAX];

int solution(int M, vector<int> &A) {
    memset(check, false, sizeof(check));
    int base = 0;
    int fibot = 0;
    int sum = 0;

    while(fibot < A.size()){

        if(check[A[fibot]]){
            base = fibot;
        }

        check[A[fibot]] = true;

   sum += fibot - base + 1;
        fibot += 1;  
    }

    return min(sum, 1000000000);
}

【问题讨论】:

    标签: c++ algorithm vector problem-steps-recorder


    【解决方案1】:

    解决方案不正确,因为您的算法错误。

    首先,让我向您展示一个反例。让A = {2, 1, 2}。第一次迭代:base = 0fibot = 0sum += 1. 没错。第二个:base = 0, fibot = 1sum += 2。这也是正确的。最后一步:fibot = 2check[A[fibot]] is true,因此,base = 2。但它应该是1。所以你的代码返回1 + 2 + 1 = 4,而正确答案1 + 2 + 2 = 5

    正确的做法可能是这样的:从L = 0 开始。对于从0n - 1 的每个R,继续向右移动L,直到子数组只包含不同的值(您可以保持数组中每个值的出现次数并使用@ 987654338@ 是唯一可以多次出现的元素)。

    您的代码还有一个问题:如果 int 在测试平台上是 32 位类型,sum 变量可能会溢出(例如,如果 A 的所有元素都是不同的)。

    至于为什么你的算法不正确的问题,我不知道为什么它首先应该是正确的。你能证明这个吗? base = fibot 分配对我来说看起来很随意。

    【讨论】:

    • 我明白了。非常感谢。
    【解决方案2】:

    100% 帮助我的 python 解决方案,感谢https://www.martinkysel.com/codility-countdistinctslices-solution/

    def solution(M, A):
        
            the_sum = 0
        
            front = back = 0
        
            seen = [False] * (M+1)
        
            while (front < len(A) and back < len(A)):
        
                while (front < len(A) and seen[A[front]] != True):
        
                    the_sum += (front-back+1)
        
                    seen[A[front]] = True
        
                    front += 1
        
                else:
        
                    while front < len(A) and back < len(A) and A[back] != A[front]:
        
                        seen[A[back]] = False
        
                        back += 1
        
                    seen[A[back]] = False
        
                    back += 1
                       
            return min(the_sum, 1000000000)  
               
    

    【讨论】:

      【解决方案3】:

      我想分享我在 C++ 中实现的算法的解释,然后是实际实现。

      1. 请注意,不同切片的最小数量为 N,因为每个元素都是一个不同的单项切片。
      2. 从第一个元素开始后退索引。
      3. 前面的索引从第一个元素开始。
      4. 向前移动,直到我们在序列中找到重复项。
      5. 在每次迭代中,将计数器递增必要的数量,这是前后的差异。
      6. 如果我们在任何迭代中达到最大计数,只需立即返回以进行轻微优化。
      7. 在序列的每次迭代中,记录已经发生的元素。
      8. 找到重复项后,将后面的索引提前一个重复项。
      9. 当我们推进后退索引时,清除所有出现的元素,因为我们在这些元素之外开始一个新切片。

      这个解决方案的运行时复杂度是O(N),因为我们经历了每一个
      元素。

      这个解决方案的空间复杂度是O(M),因为我们有一个哈希要存储 序列中出现的元素。这个哈希的最大元素是 M。

      int solution(int M, vector<int> &A)                                             
      {                                                                               
        int N = A.size();                                                             
        int distinct_slices = N;                                                      
        vector<bool> seq_hash(M + 1, false);                                          
        for (int back = 0, front = 0; front < N; ++back) {                            
          while (front < N and !seq_hash[A[front]]) { distinct_slices += front - back; if (distinct_slices > 1000000000) return 1000000000; seq_hash[A[front++]] = true; }
          while (front < N and back < N and A[back] != A[front]) seq_hash[A[back++]] = false;
          seq_hash[A[back]] = false;                                                  
        }                                                                             
                                                                                      
        return distinct_slices;                                                       
      }
      

      【讨论】:

        【解决方案4】:

        100% 使用 Ruby 的解决方案

        LIMIT = 1_000_000_000
        
        def solution(_m, a)
          a.each_with_index.inject([0, {}]) do |(result, slice), (back, i)|
            return LIMIT if result >= LIMIT
            slice[back] = true
            a[(i + slice.size)..-1].each do |front|
              break if slice[front]
              slice[front] = true
            end
            slice.delete back
            [result + slice.size, slice]
          end.first + a.size
        end
        

        【讨论】:

        • 没有解释,只是随机代码,很少是最好的教育目的。
        【解决方案5】:

        使用 Caterpillar 算法和公式 S(n+1) = S(n) + n + 1 其中S(n)n 的切片计数 - 元素数组 java 解决方案可能是:

         public int solution(int top, int[] numbers) {
                int len = numbers.length;
                long count = 0;
        
                if (len == 1) return 1;
        
                int front = 0;
                int[] counter = new int[top + 1];
        
                for (int i = 0; i < len; i++) {
                    while(front < len && counter[numbers[front]] == 0 ) {
                        count += front - i + 1;
                        counter[numbers[front++]] = 1;
                    }
        
                    while(front < len && numbers[i] != numbers[front] && i < front) {
                        counter[numbers[i++]] = 0;
                    }
        
                    counter[numbers[i]] = 0;
        
                    if (count > 1_000_000_000) {
                        return 1_000_000_000;
                    }
                }
        
                return count;
            }
        

        【讨论】:

          猜你喜欢
          • 2022-11-05
          • 2020-01-05
          • 2013-04-27
          • 1970-01-01
          • 2020-09-24
          • 2012-11-10
          • 1970-01-01
          • 2015-01-19
          • 1970-01-01
          相关资源
          最近更新 更多