简体   繁体   English

查找区间内回文数的算法

[英]Algorithm to find number of palindromes in interval

I'm currently tasked with writing a program that calculates amount of palindromes in any base from interval of <2;36> .我目前的任务是编写一个程序,从<2;36>的间隔计算任何基数的回文数。 The problem is that my solution has time complexity of O(n^2) at best and that is, if I was frank, really slow.问题是我的解决方案充其量只有O(n^2)的时间复杂度,也就是说,如果我坦率地说,真的很慢。

So far I've tried naive solutions such as converting all numbers from the interval to the base that is required, saving the conversion of the number to array and then checking each of the elements one by one.到目前为止,我已经尝试过一些简单的解决方案,例如将所有数字从区间转换为所需的基数,将数字转换为数组,然后一一检查每个元素。

This is what I've got so far:这是我到目前为止所得到的:

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;
   }
}

It is not good by any stretch, but it does work for the basic test.无论如何它都不好,但它确实适用于基本测试。 The problem is that I'm currently trying to solve bonus one which works with much bigger numbers.问题是我目前正在尝试解决适用于更大数字的奖金之一。

By much bigger numbers I mean intervals that span billions of numbers, one of the inputs is for example this:通过更大的数字,我的意思是跨越数十亿数字的间隔,其中一个输入是例如:

c 15 62103360044 155888062462
Result : 123502

Where c is task that the program is supposed to do (there was option of l which listed all palindromes which doesn't occur in the bonus tests), 15 is base and the two other numbers are the limits of the interval.其中 c 是程序应该执行的任务(有 l 选项列出了在奖励测试中没有出现的所有回文),15 是基数,另外两个数字是间隔的限制。

I'm supposed to count palindromes of five such intervals under one second and honestly, I'm pretty stuck.我应该在一秒钟内计算五个这样的间隔的回文,老实说,我很困惑。

I would appreciate any help, I'm sorry if I formatted my question wrongly or if it was too drawn out - This is the first time I've asked a question here.我会很感激任何帮助,如果我的问题格式错误或过于冗长,我很抱歉 - 这是我第一次在这里提出问题。

  • Doing a palindrome check faster is a minor optimisation.更快地进行回文检查是一个的优化。 Initially I would even use java's number to String conversion.最初我什至会使用 java 的数字到字符串的转换。

  • What you want is to step through the interval in larger leaps.你想要的是在更大的飞跃中跨过这个区间。

  • You can use recursion for simplification in the initial version of your algorithm.您可以在算法的初始版本中使用递归进行简化。

Let's look for base 10:让我们寻找以 10 为底的:

 62_103_360_044
155_888_062_462

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

You need:你需要:

  • Number of digits (your counter )位数(您的counter
  • First most significant digit第一个最高有效数字
  • Parameters start and end参数开始和结束

For this step you only need to increment one digit, which even may be done as char.对于这一步,您只需要增加一个数字,甚至可以作为 char 完成。

Notice also that the recursive call on... gives the same result for 7, 8 and 9 with start 000..000 and end 999..999.另请注意,对...的递归调用对 7、8 和 9 给出相同的结果,开始 000..000 和结束 999..999。

This will be tremendously faster.这将大大加快。 Happy coding.快乐编码。


Usage of recursion: I am not giving a clean answer, as that would defeat the task's challenge.递归的使用:我没有给出一个明确的答案,因为这会打败任务的挑战。

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;
}

Recursion calling oneself, here only once, without extra parameters, which often are used.递归调用自己,这里只调用一次,没有额外的参数,经常用到。 For instance it is much easier to split the work in:例如,将工作拆分为:

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

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

And calculate for every X并计算每个 X

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

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

For that you need a level of abstraction/simplification.为此,您需要一定程度的抽象/简化。 Keep-it-simple.把事情简单化。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM