什么是这个难题的更有效的实现?

时间:2014-11-23 14:02:14

标签: algorithm puzzle

难题

对于每个输入数n(n <10),存在输出数m,使得:

  • m的第一个数字是n
  • m是n位数字
  • m内的每2位数序列必须是不同的素数

输出应为m,其中m是满足上述条件的最小数。如果没有这样的数字,则输出应为-1;

示例

n = 3 - &gt; m = 311

n = 4 - &gt; m = 4113(请注意,这不是4111,因为它将重复11)

n = 9 - &gt; m = 971131737

我有点工作的解决方案

这是我对此的第一次尝试,即“蛮力”方法。我正在寻找一种更优雅的解决方案,因为随着n变大,效率非常低。

public long GetM(int n)
{
    long start = n * (long)Math.Pow((double)10, (double)n - 1);
    long end = n * (long)Math.Pow((double)10, (double)n);
    for (long x = start; x < end; x++)
    {
        long xCopy = x;
        bool allDigitsPrime = true;
        List<int> allPrimeNumbers = new List<int>();
        while (xCopy >= 10)
        {
            long lastDigitsLong = xCopy % 100;
            int lastDigits = (int)lastDigitsLong;
            bool lastDigitsSame = allPrimeNumbers.Count != 0 && allPrimeNumbers.Contains(lastDigits);
            if (!IsPrime(lastDigits) || lastDigitsSame)
            {
                allDigitsPrime = false;
                break;
            }

            xCopy /= 10;
            allPrimeNumbers.Add(lastDigits);
        }

        if (n != 1 && allDigitsPrime)
        {
            return x;
        }
    }

    return -1;
} 

关于如何提高效率的初步想法

所以,显然这里的瓶颈是遍历整个数字列表,这些数字可以满足这个条件从n ....到(n + 1)....除了简单地增加循环的每次迭代的次数之外,必须有一些聪明的方法来根据2位数序列必须是素数的要求来跳过数字。例如,对于n = 5,没有点经过50000 - 50999(50不是素数),51200 - 51299(12不是素数),但我不太确定如何实现这一点或者如果它这将足以使算法运行n = 9。

有关此方法或不同优化方法的任何想法?

3 个答案:

答案 0 :(得分:3)

您不必尝试所有号码。你可以使用不同的策略,总结为&#34;尝试追加数字&#34;。

哪个数字?好吧,这样的数字

  1. 它与您当前的最后一位数字一起形成一个素数
  2. 形成的素数未出现在
  3. 之前的数字中

    这应该以递归方式(而不是迭代方式)完成,因为您可能会用完选项,然后您必须回溯并在数字的前面尝试不同的数字。

    这仍然是指数时间算法,但它避免了大部分搜索空间,因为它从不尝试任何不符合规则的数字,即每对相邻数字必须形成素数。

答案 1 :(得分:2)

这是R中使用递归的可能解决方案。构建所有可能路径的树

会很有趣
# For every input number n (n < 10) 
# there is an output number m such that:

#  m's first digit is n
#  m is an n digit number
#  every 2 digit sequence inside m must be a different prime number
# Need to select the smallest m that meets the criteria

library('numbers')

mNumHelper <- function(cn,n,pr,cm=NULL)  {
  if (cn == 1) {
    if (n==1) {
      return(1)
    }
    firstDigit <- n
  } else {
    firstDigit <- mod(cm,10)
  }
  possibleNextNumbers <- pr[floor(pr/10) == firstDigit]
  nPossible = length(possibleNextNumbers)
  if (nPossible == 1) {
    nextPrime <- possibleNextNumbers
  } else{
    # nextPrime <- sample(possibleNextNumbers,1)
    nextPrime <- min(possibleNextNumbers)
  }
  pr <- pr[which(pr!=nextPrime)] 
  if (is.null(cm)) {
    cm <- nextPrime
  } else {
    cm = cm * 10 + mod(nextPrime,10)
  }
  cn = cn + 1
  if (cn < n) {
    cm = mNumHelper(cn,n,pr,cm)
  }
  return(cm)
}

mNum <- function(n) {
  pr<-Primes(10,100)
  m <- mNumHelper(1,n,pr)  
}
for (i in seq(1,9)) {
  print(paste('i',i,'m',mNum(i)))
}

示例输出

[1] "i 1 m 1"
[1] "i 2 m 23"
[1] "i 3 m 311"
[1] "i 4 m 4113"
[1] "i 5 m 53113"
[1] "i 6 m 611317"
[1] "i 7 m 7113173"
[1] "i 8 m 83113717"
[1] "i 9 m 971131737"

更新解决方案以从可用素数集中选择最小素数,并删除错误路径检查,因为它不是必需的。

答案 2 :(得分:0)

我刚刚列出了两位数的素数,然后手工解决问题;它只用了几分钟。不是每个问题都需要一台电脑!