【问题标题】:Algorithm to find number of palindromes in interval查找区间内回文数的算法
【发布时间】:2019-10-28 14:30:13
【问题描述】:

我目前的任务是编写一个程序,从<2;36> 的区间计算任何基数的回文数。问题是我的解决方案的时间复杂度最多为O(n^2),也就是说,如果我坦率地说,真的很慢。

到目前为止,我尝试了一些简单的解决方案,例如将所有数字从区间转换为所需的基数,将数字转换为数组,然后一一检查每个元素。

这是我到目前为止所得到的:

int isTrue = 1;
int arr[64];

while(n > 0)
{
   arr[counter] = n % base;
   n = n / base;
   counter++;
}

for(int i = 0; i < counter; i ++)
{
   if(arr[i] != arr[counter - i - 1])
   {
      isTrue = 0;
      break;
   }
}

这无论如何都不好,但它确实适用于基本测试。问题是我目前正在尝试解决适用于更大数字的奖金之一。

我指的是跨越数十亿个数字的区间,其中一个输入是例如:

c 15 62103360044 155888062462
Result : 123502

其中 c 是程序应该执行的任务(有选项 l 列出了在奖励测试中不会出现的所有回文),15 是基数,另外两个数字是间隔的限制。

我应该在一秒钟内数出五个这样的间隔的回文,老实说,我很困惑。

如果我的问题格式错误或过于冗长,我将不胜感激 - 这是我第一次在这里提出问题。

【问题讨论】:

  • 不到一秒O(log n)是不同的要求。你有哪个?
  • 不到一秒
  • 那么标题中的内容是什么?删除它,因为它看起来不真实。
  • 无论如何,您宁愿通过迭代数字的前半部分来生成一个回文列表 - 自然后半部分将是相同的数字反转。因此,如果您稍微考虑一下,您甚至可能会想出一个花费大约零时间的分析解决方案。
  • 重新“逐一检查每个元素”:什么?不。如果间隔是十进制,从 100000 到 999,999,那么正好有 900 个回文。您不需要单独计算它们。如果前三位数字是 100,则有一个以这种方式开始的回文数,即 100,001。对于 101,还有一个:101,101。如果基数是 16,那么从 100,000 到以 16 为基数的 FFF,FFF,有 F00(以 16 为基数)回文串(十进制 3840)。您需要做的是弄清楚如何以不规则的间隔(如 1234 到 6972)计算回文数,而不是单独计算。

标签: c optimization palindrome base


【解决方案1】:
  • 更快地进行回文检查是一个次要优化。 最初我什至会使用 java 的数字到字符串的转换。

  • 你想要的是以更大的跳跃跨越间隔。

  • 您可以在算法的初始版本中使用递归进行简化。

让我们寻找以 10 为底的:

 62_103_360_044
155_888_062_462

 6 ...        6 (recursion on the middle part)
 7 ...        7
 8 ...        8
 9 ...        9
1 ...         1

你需要:

  • 位数(您的counter
  • 第一个最高有效数字
  • 参数开始和结束

对于这一步,您只需要增加一位数字,甚至可以作为字符完成。

还请注意,对 ... 的递归调用对于 7、8 和 9 给出相同的结果,开始 000..000 和结束 999..999。

这将大大加快。编码愉快。


递归的使用: 我没有给出明确的答案,因为这会破坏任务的挑战。

public BigInteger palindromesInInterval(int base, BigInteger from, BigInteger to) {
    return palindromesRec(base, from.toString(base), to.toString(base));
}

private BigInteger palindromesRec(int base, String from, String to) {
    // Do the simple work:
    if (from.length() > to.length()) {
        return BigInteger.ZERO;
    }
    if (from.length() == to.length() && from.compareTo(to) > 0) {
        return BigInteger.ZERO;
    }
    if (from.length() == 1) {
        ...
    }
    // Do a step:
    int highDigit = Integer.parseInt(from.substring(0, 1), base);
    int lowDigit = Integer.parseInt(from.substring(from.length() - 1), base);

    BigInteger sum = BigInteger.ZERO;
    int digit = Math.max(highDigit, lowDigit);
    String from2 = from.substring(1, from.length() - 2); // Can start with 0
    String to2 = "1000...000" -1; // Niners so to say.
    while (digit < base) {
         ...
         sum = sum.add(palidromesRec(base, from2, to2)); // RECURSION
         from2 = "000...000";
    }
    ...
    return sum;
}

递归调用自己,这里只调用一次,没有多余的参数,经常用到。例如,将工作拆分为:

from  6 2_103_360_04 4
  to  9 9 ..       9 9

from 1 00 ..       0 1
  to 1 55_888_062_46 2

并为每个 X 计算

from X 000 X   (n zeroes)
  to X 999 X   (n time (base-1))

作为基础(n+1)/2.

为此,您需要一定程度的抽象/简化。保持简单。

【讨论】:

  • 对不起,但我不确定我是否完全遵循:在数字的中间部分使用递归并以更大的步长逐步通过间隔是什么意思?我
  • 递归处理了吗?只做一点点,周围的数字,然后通过更少的工作调用自己(克隆)。
猜你喜欢
  • 1970-01-01
  • 2023-01-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-05-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多