【问题标题】:What is simplest way to find repeat unit of array?找到数组重复单元的最简单方法是什么?
【发布时间】:2016-09-04 20:13:12
【问题描述】:

例如,重复单元

1,1,1,1,1

是 1,

重复单位

1,3,2,1,3,2,1,3,2

是 1,3,2

重复单位

1,3,2,1,3,9,1,3,2

是 1,3,2,1,3,9,1,3,2

我尝试这样的想法:

1.尝试从1开始重复单元测试的次数,直到数组的大小

2.只尝试数组大小的倍数,例如:n

3.检查n是否为重复单元的大小,例如:假设测试重复单元为3,然后检查是否

a[0]==a[3*1],a[1]==a[1+3*1],a[2]==a[2+3*1]
a[0]==a[3*2],a[1]==a[1+3*2],a[2]==a[2+3*2]
a[0]==a[3*r],a[1]==a[1+3*r],a[2]==a[2+3*r]
  1. 如果当前测试数是重复单元,break,当前i的值为重复单元的大小

我尝试将其转换为代码:

#include <stdio.h>
int main(){
    int a[]={1,3,2,1,3,2,1,3,2};
    int i;
    //1.try number of repeat unit test from 1,until the size of array
    for(i=1;i<=sizeof(a)/sizeof(int);i++){
        //2.only try number which is multiple of the size of array,e.g.: n
        int n=sizeof(a)/sizeof(int);
        if(n%i==0){
            //3.check if n is the size of repeat unit
            bool isRepeat=true;
            for(int j=0;j<n;j++){
                for(int r=1;r<i;r++){
                    if(a[j]!=a[j+r*n]){
                        isRepeat=false;
                        break;
                    }
                }
            }
            //4.if the current testing number is repeat unit, break, and the current value of i is the size of repeat unit
            if(isRepeat){
                break;
            }
        }
    }

    //print the result using repeat unit n
    for(int n=0;n<i;n++){
        printf("%d ",a[n]);
    }
};

但它显示 1,3,2,1,3,2,1,3,2 的重复单元是 1 而不是 1,3,2。而且我认为这个解决思路太复杂了,因为它有太多的 for 循环。有没有更简单的方法或算法来查找数组的重复单元?

【问题讨论】:

    标签: c++ arrays algorithm language-agnostic


    【解决方案1】:

    您可以在此处使用 STL 设置功能。就这样,

    int main()
    {
    set< int > s;
      s.insert(1);
      s.insert(3);
      s.insert(2);
      s.insert(1);
      s.insert(3);
      s.insert(2);
      s.insert(1);
      s.insert(3);
      s.insert(2);
    
       set< int > :: iterator it;
       for(it = s.begin(); it != s.end(); it++) {
        cout << *it << endl;
    }
    

    它将打印不同的元素,因此您将找到任何数组的重复单元。 快乐编码!

    【讨论】:

      【解决方案2】:

      这里的错误在于您首先检查 i 为 1 的情况,当然这将被检测为您的重复单元。 那是因为这条线

      for(int r=1;r<i;r++)
      

      如果i=1(您的第一个案例)将立即中断。

      如果您确定您的数字将介于 0 和 9 之间(即,只有一位数)并且您想要一个“简单”的解决方案(正如您在标题中所说),您可以使用数字构建一个字符串,将字符串拆分为子字符串并检查它们是否彼此相等。

      #include <stdio.h>
      #include <string.h>
      
      int main(){
          int nums[]={1,3,2,1,3,2,1,3,2};
          char initial_string[255];
          char string_list[255][255];
          int i, j, k, l;
          int found = 0;
      
          memset(initial_string, 0, 255);
          for(i=0; i < sizeof(nums)/sizeof(int); i++) {
              initial_string[i] = '0' + nums[i];
          }
      
          int n = sizeof(nums)/sizeof(int);
          memset(string_list, 0, 255*255);
      
          for(i = 1; i <= n; i++) {
              if (n%i == 0) {
                  int count = (int)n/i;
                  for (k = 0, j = 0; k < n; k+=i, j++) {
                      strncpy(string_list[j], &initial_string[k], i);
                  }
                  found = 1;
                  for (k = 0; k < count; k++) {
                      if (strcmp(string_list[0], string_list[k])) {
                          // Different strings!
                          found = 0;
                          break;
                      }
                  }
              }
              if (found) {
                  break;
              }
          }
      
          printf("Repeat unit: %d\n", i);
      }
      

      请注意,此代码不是最佳的,有几处需要改进,将其作为一个总体思路。

      【讨论】:

        【解决方案3】:

        您的if(a[j]!=a[j+r*n]) 似乎有错误

        为什么要加n?不应该是:if(a[j]!=a[j+r*i])

        此外,该算法有点慢,解决它的另一种方法是将每个数字视为字符串中的不同字符,并使用 Knuth Morris-Pratt (KMP) 算法。 (https://en.wikipedia.org/wiki/Knuth%E2%80%93Morris%E2%80%93Pratt_algorithm)

        很快就会在答案中添加更多信息。

        更新:

        免责声明:语法和变量可能不完整

        KMP 实施:

        int F[MAX_N];
        int main(void){
            int P[MAX_N], T[MAX_N];
            //1. get input, put it into P array, not coded.
            //....
            //2. insert content of P array to T twice.
            int ptr = 0;
            for(int i = 0;i<2;i++)
                for(int j = 0;j<length_of_p;j++){
                    T[ptr++] = P[j];
                }
            //3. get length of repeated unit.
            int repeated = kmp(P, T, 1);
            //4. print the numbers of repeated unit. i.e. done
            cout<<"REPEATED UNIT: ";
            for(int i = 0;i<repeated;i++)
                cout<< P[i] << " ";
            cout<<endl;
        
            return 0;
        }
        void kmp_init(int P[]) {
            F[0] = 0;  F[1] = 0;  
            int i = 1, j = 0;
            while(i<P.size()) {
                if (P[i] == P[j])
                    F[++i] = ++j;
                else if (j == 0)
                    F[++i] = 0;
                else
                    j = F[j];
            }
        }
        
        int kmp(int P[], int T[], int start) {
            kmp_init(P);
            int i = start, j = 0;
            int n = T.size(), m = P.size();
        
            while(i-j <= n-m) {
                while(j < m) {
                    if (P[j] == T[i]) {
                        i++; j++;
                    } else break;
                }
                if (j == m) return i-m;
                else if (j == 0) i++;
                j = F[j];
            }
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2011-08-30
          • 1970-01-01
          • 1970-01-01
          • 2021-11-11
          相关资源
          最近更新 更多