查找长度高达10000的字符串的子序列

Find subsequences of a string whose length is as large as 10,000

本文关键字:字符串 10000 高达 查找      更新时间:2023-10-16

我有一个字符串,其大小可以大到"10000"。我必须数那些能被9整除的子项。

子序列:子序列是一种排列,其中保持给定字符串的顺序。例如:如果给定字符串是10292,那么它的一些子序列是1、102、10、19、12、12(12是2的两倍)、129、029、09、092等。一些不是给定字符串子序列的数字是:201(2和0不能在1之前)、921、0291等。

我试着通过比特移位生成给定字符串的所有子序列(幂集),并检查每个字符串是否可以被9整除。但只要字符串的长度<10.在那之后,我没有得到合适的子序列(有些子序列显示为负数)。

以下是我的代码:

    scanf("%s", &str); //input string 
    int n=strlen(str); //find length of string
    //loop to generate subsequences
    for(i=1;i<(1<<n);++i){
        string subseq;
        for(j=0;j<n;++j){
            if(i&(1<<j)){
                subseq+=str[j]; // generate subsequence
            }
        }
        //convert generated subseq to int; number is 'long' tpye
        number=atol(subseq.c_str());printf("%ldn", number); 
        //ignore 0 and check if number divisible by 9
        if(number!=0&&number%9==0)count++;
    }
        printf("%ldn", count);

由于一个数字可以被九整除,当且仅当其数字之和可以被九除时,您可以使用O(n)递归算法来解决这个问题。

其思想如下:在每一步,将子序列一分为二,并(递归地)确定有多少序列的数字之和为i % 9,其中i的范围从08。然后,通过以下方式"合并"O(1)中的两个表,为整个范围构建这个完全相同的表。假设L是左拆分的表,R是右拆分的表。您需要为整个范围构建表F

然后你有:

for (i = 0; i < 9; i++) {
  F[i] = L[i] + R[i];
  for (j = 0; j < 9; j++) {
    if (j <= i)
      F[i] += L[j] * R[i - j]
    else
      F[i] += L[j] * R[9 + i - j]
  }
}

只有一个数字d的子序列的基本情况是显而易见的:只需将F[d % 9] = 1和所有其他条目设置为零。

完整的C++11实现:

#include <iostream>
#include <array>
#include <tuple>
#include <string>
typedef std::array<unsigned int, 9> table;
using std::tuple;
using std::string;
table count(string::iterator beg, string::iterator end)
{
    table F;
    std::fill(F.begin(), F.end(), 0);
    if (beg == end)
        return F;
    if (beg + 1 == end) {
        F[(*beg - '0') % 9] = 1;
        return F;
    }
    size_t distance = std::distance(beg, end);
    string::iterator mid = beg + (distance / 2);
    table L = count(beg, mid);
    table R = count(mid, end);
    for (unsigned int i = 0; i < 9; i++) {
        F[i] = L[i] + R[i];
        for(unsigned int j = 0; j < 9; j++) {
            if (j <= i)
                F[i] += L[j] * R[i - j];
            else
                F[i] += L[j] * R[9 + i - j];
        }
    }
    return F;
}
table count(std::string s)
{
    return count(s.begin(), s.end());
}
int main(void)
{
    using std::cout;
    using std::endl;
    cout << count("1234")[0] << endl;
    cout << count("12349")[0] << endl;
    cout << count("9999")[0] << endl;
}

我有个主意!

由于您只需要计数子字符串,所以您不在乎它们实际上是什么。因此,你可以只存储它们可能的总和。

那么,如果你有一个函数,可以组合两个子字符串集的计数表,并给出它们组合的计数,会怎么样?

既然我知道这是一个可怕的解释,我就举一个例子。假设你得到了一个号码:

2493

将其一分为二,并继续拆分,直到得到单个数字:

   2493
   /  
 24    93
 /    /
2  4  9  3

2的总和是多少?简单:2。而4只能和4求和。您可以构建每个值的子字符串总数表(mod 9):

   0 1 2 3 4 5 6 7 8
2: 0 0 1 0 0 0 0 0 0
4: 0 0 0 0 1 0 0 0 0
9: 1 0 0 0 0 0 0 0 0
3: 0 0 0 1 0 0 0 0 0

把两张桌子放在一起很容易。将第一个表、第二个表和两个mod 9的每个组合相加(对于第一个组合,这相当于2424;对于第二个组合,9393):

    0 1 2 3 4 5 6 7 8
24: 0 0 1 0 1 0 1 0 0
93: 1 0 0 2 0 0 0 0 0

然后再做一次:

      0 1 2 3 4 5 6 7 8
2493: 3 0 2 2 2 2 2 2 0

这就是你的答案,坐在0栏里:3。这对应于子串24324939。不过,你不知道,因为你只存储了计数——幸运的是,你不在乎!

一旦实现,这将为您提供O(n)性能——您只需要弄清楚如何在O(1)中组合表。但是嘿,作业,对吧?祝你好运

如果使用int,则不应将其左移太多。如果你这样做了,你就设置了符号位。使用unsigned int。或者不要太左移。如果您坚持int,则可以在完成后右移。

对于

printf("%ldn", count); 

printf在显示长int类型时可能会出现问题。你试过cout吗?

下面是根据Akappa算法编写的C++代码。然而,该算法对包含一个或多个0的数字失败,即在"10292"answers"0189"的情况下,但对"1292"answers"189"给出了正确答案。如果有人能调试它,为所有情况提供答案,我将不胜感激。

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<string>
#include<cstring>
#include<vector>
#include<stack>
#include<sstream>
#include<algorithm>
#include<cctype>
#include<list>
#include<set>
#include<set>
#include<map>
using namespace std;
typedef vector<int> table;
table count(string::iterator beg, string::iterator end)
{
    table F(9);
    std::fill(F.begin(), F.end(), 0);
    if (beg == end)
        return F;
    if (beg + 1 == end) {
        F[(*beg - '0') % 9] = 1;
        return F;
    }
    size_t distance = std::distance(beg, end);
    string::iterator mid = beg + (distance / 2);
    table L = count(beg, mid);
    table R = count(mid, end);
    for (unsigned int i = 0; i < 9; i++) {
        F[i] = L[i] + R[i];
        for(unsigned int j = 0; j < 9; j++) {
            if (j <= i)
                F[i] += L[j] * R[i - j];
            else
                F[i] += L[j] * R[9 + i - j];
        }
    }
    return F;
}
table count(std::string s)
{
    return count(s.begin(), s.end());
}
int main()
{

     cout << count("1234")[0] << endl;
    cout << count("12349")[0] << endl;
    cout << count("9999")[0] << endl;
    cout << count("1292")[0] << endl;cout << count("189")[0] << endl;
    cout << count("10292")[0] << endl;cout << count("0189")[0] << endl;
    system("pause");

   }