java 素数群的计数

jvidinwx  于 2022-12-17  发布在  Java
关注(0)|答案(2)|浏览(143)

给定一个输入字符串,按照输入字符串中给定的顺序将其拆分为素数组,每组包含输入字符串中的所有字符,求出这些组的个数。

示例:

11375

答复:

3

说明:

这3种组合是[11,37,5][11,3,7,5][113,7,5]

我尝试的密码

public int countPossibilities(String s) {
    int n = s.length();
    int[] ar = new int[n + 1];
    ar[0] = 1;
    for (int i = 1; i < n; i++) {
        int j = i - 1;
        while (j >= 0 && j >= i - 3) {
            if (prime(s.substring(j, i)))
                ar[i] += ar[j];

            j--;
        }
    }

    return ar[n];
}

public boolean prime(String s) {
    int n = Integer.parseInt(s);
    if (n < 2) return false;

    for (int i = 2; i * i <= n; i++)
        if (n % i == 0) return false;

    return true;
}

如果输入字符串的长度很小,这种方法就可以正常工作。
但是输入字符串的长度可以从1到10^5,所以我的程序对大字符串失败。

示例:

1350297079989171477791892123929141605573631151125933376097791877830238462471373933362476484818693477173990672289892448124097556197582379957168911392680312103962394732707409889862447273901522659
预期结果为:4386816
解决这个问题的正确方法是什么。

mbjcgjjk

mbjcgjjk1#

下面的Python代码可以回答这个长示例。
dp[i]表示在输入的第i个索引处结束的有效组合的数目,然后对于在input[i]处结束的长度为x的每个素数后缀,我们将在dp[i-x]处结束的有效组合的计数添加到dp[i],前提是还存在针对dp[i-x]记录的有效组合的计数。

# https://rosettacode.org/wiki/Sieve_of_Eratosthenes
def primes2(limit):
    if limit < 2: return []
    if limit < 3: return [2]
    lmtbf = (limit - 3) // 2
    buf = [True] * (lmtbf + 1)
    for i in range((int(limit ** 0.5) - 3) // 2 + 1):
        if buf[i]:
            p = i + i + 3
            s = p * (i + 1) + i
            buf[s::p] = [False] * ((lmtbf - s) // p + 1)
    return set(["2"] + [str(i + i + 3) for i, v in enumerate(buf) if v])

def f(n):
  # The constant, k, limits the number
  # of digits in the suffix we're
  # checking for primality.
  k = 6
  primes = primes2(10**k)
  dp = [0] * len(n) + [1]
  for i in range(len(n)):
    suffix = ""
    for j in range(min(i + 1, k)):
      suffix = n[i-j] + suffix
      if suffix in primes and dp[i-j-1] > 0:
        dp[i] += dp[i-j-1]
  return dp[len(n) - 1]

输出:

n = "1350297079989171477791892123929141605573631151125933376097791877830238462471373933362476484818693477173990672289892448124097556197582379957168911392680312103962394732707409889862447273901522659"

print(f(n)) # 4386816
efzxgjgh

efzxgjgh2#

概念证明来自我的评论,但在C#(我是一个AP的Comp Sci老师,不喜欢用Java编码;想想看!):
取输入字符串的长度减1,并将此称为“padLength”,现在将2的padLength次幂取为字符串组合的可能性总数;接下来,从0计数到numberOfCombinations,并将该十进制数转换为二进制数,用零填充到padLength,称为“binaryNumber”。二进制数表示是否应该在原始数的数字之间添加空格。例如,二进制的“1100”和十进制的“11375”会得到“1 1 375”,因为1表示在中间放一个空格。这个过程会给予你原始字符串在不同分组中的所有组合。然后你可以从分组中提取数字,看看它们是否是素数...
代码:

private async void button1_Click(object sender, EventArgs e)
{
    if (textBox1.Text.Trim().Length == 0) { return; }

    textBox1.Enabled = false;
    button1.Enabled = false;
    textBox2.Clear();

    String binary;
    StringBuilder sb = new StringBuilder();
    String input = textBox1.Text.Trim();
    char[] digits = input.ToCharArray();
    int padLength = input.Length - 1;
    long combinations = (long)Math.Pow(2, padLength);

    List<String> combos = new List<string>();
    await Task.Run(() => {
        for (long i = 0; i < combinations; i++)
        {
            binary = Convert.ToString(i, 2).ToString().PadLeft(padLength, '0');
            char[] binaryDigits = binary.ToCharArray();

            sb.Clear();
            for (int s = 0; s < digits.Length; s++)
            {
                sb.Append(digits[s]);
                if (s < (digits.Length - 1))
                {
                    if (binaryDigits[s] == '1')
                    {
                        sb.Append(' ');
                    }
                }
            }

            combos.Add(sb.ToString());
        }
    });
    
    textBox2.Lines = combos.ToArray();
    textBox1.Enabled = true;
    button1.Enabled = true;
}

输出:

对于非常大的输入,您将无法使用Math.Pow计算组合的数量()或任何用于将十进制数转换为二进制数的内置方法。在这些情况下,您可以直接使用字符串并遵循计数算法,以二进制“手动计数”。我只使用String操作直接构建二进制数,方法是检查每个字符,看看它是1还是0,然后相应地进行操作。当你有一个1的字符串的长度比你输入的长度小1时,你就完成了。这将比直接处理数字慢得多。

相关问题