java 中的超级回文

Super Palindromes in java

此代码的运行时间为 269 毫秒,谁能帮助我降低此解决方案的复杂性?

输入:左=“4”,右=“1000”

输出:4

解释:4、9、121、484是超级回文。 注意676不是超级回文:26 * 26 = 676,但是26不是回文。

class Solution {
    public int superpalindromesInRange(String left, String right) {     
        int FIX = 100000;
        int ans = 0;
        long L = Long.valueOf(left);
        long R = Long.valueOf(right);
        // Odd palindrome 1234321
        for(int i = 1; i < FIX; i++){
            StringBuilder str = new StringBuilder(Integer.toString(i));
             for (int j = str.length() - 2; j >= 0; j--)
                str.append(str.charAt(j));
            long p = Long.valueOf(str.toString());
            long p_square = p * p;
            if(p_square > R) break;
            if(p_square >= L && isPalindrome(p_square)) ans++;
        }
        //even palindrome 12344321
        for(int i = 1; i < FIX; i++){
            StringBuilder str = new StringBuilder(Integer.toString(i));
            for (int j = str.length() - 1; j >= 0; j--)
                str.append(str.charAt(j));
            long p = Long.valueOf(str.toString());            
            long p_square = p * p;
            if(p_square > R) break;
            if(p_square >= L && isPalindrome(p_square)) ans++;
        }
        return ans;
    }
    public boolean isPalindrome(long val){
        long res = 0;
        long temp = val;
        // System.out.println(val);
        while(temp > 0){
            res = 10 * res + temp % 10;
            temp = temp / 10;
        }
        return res == val;
    }
}

我不明白 super palindrome 部分。
但是,这是 isPalindrome:

的一个更简单的实现
public boolean isPalindrome(long val) {

    char[] buf = Long.toString(val).toCharArray();

    for (int i = 0, j = buf.length - 1, iMax = buf.length >> 1; i < iMax; ++i) {
        if (buf[i] != buf[j - i])
            return false;
    }

    return true;
}

顺便说一句,用Long.parseLong代替Long.valueOf

  • Long.parseLong returns long(原始类型)
  • Long.valueOf returns Long (object)

编辑 1

我理解你的isPalindrome方法并做了一些性能测试。

start = System.currentTimeMillis();
for (long xx = 1L; xx < 100000000L; ++xx)
    isPalindrome(xx); // Your implementation
System.out.println((System.currentTimeMillis() - start) + " ms.");

start = System.currentTimeMillis();
for (long xx = 1L; xx < 100000000L; ++xx)
    isPalindrome_(xx); // My implementation
System.out.println((System.currentTimeMillis() - start) + " ms.");

结果:

1877 ms.
3805 ms.

你的实现比我的快。

编辑 2

你的算法很干净,我通过移出循环 for StringBuilder:

的实例化发现了一点改进
public int superpalindromesInRange(String left, String right) {

    StringBuilder str = new StringBuilder();

    int ans = 0;
    long L = Long.parseLong(left);
    long R = Long.parseLong(right);
    
    // Odd palindrome 1234321
    for (int i = 1; i < Integer.MAX_VALUE; i++) {
        str.setLength(0);
        str.append(i);
        for (int j = str.length() - 2; j >= 0; j--)
            str.append(str.charAt(j));
        long p = Long.parseLong(str.toString());
        long p_square = p * p;
        if (p_square > R)
            break;
        if (p_square >= L && isPalindrome(p_square))
            ans++;
    }
    
    // Even palindrome 12344321
    for (int i = 1; i < Integer.MAX_VALUE; i++) {
        str.setLength(0);
        str.append(i);
        for (int j = str.length() - 1; j >= 0; j--)
            str.append(str.charAt(j));
        long p = Long.parseLong(str.toString());
        long p_square = p * p;
        if (p_square > R)
            break;
        if (p_square >= L && isPalindrome(p_square))
            ans++;
    }
    return ans;
}

我进行了大值性能测试:

long left = 4L;
long right = 1000000000L;

System.out.println("Warmup:");
start = System.currentTimeMillis();
for (int xx = 0; xx < 10000; ++xx)
    superpalindromesInRange(Long.toString(left), Long.toString(right));
System.out.println((System.currentTimeMillis() - start) + " ms.");

start = System.currentTimeMillis();
for (int xx = 0; xx < 10000; ++xx)
    superpalindromesInRange2(Long.toString(left), Long.toString(right));
System.out.println((System.currentTimeMillis() - start) + " ms.");

System.out.println("Test:");
start = System.currentTimeMillis();
for (int xx = 0; xx < 10000; ++xx)
    superpalindromesInRange(Long.toString(left), Long.toString(right));
System.out.println((System.currentTimeMillis() - start) + " ms.");

start = System.currentTimeMillis();
for (int xx = 0; xx < 10000; ++xx)
    superpalindromesInRange2(Long.toString(left), Long.toString(right));
System.out.println((System.currentTimeMillis() - start) + " ms.");

结果:

Warmup:
675 ms.
335 ms.
Test:
372 ms.
204 ms.

通过在 for 循环之外实例化 StringBuilder,执行时间几乎减半。

先生成超级回文的平方根。然后平方,看这个平方是不是也是回文

要生成平方根,您首先需要一个下限和一个上限。使用左边的平方根的天花板和右边的平方根的地板。接下来尝试只生成确实是回文的数字。在您的示例中,界限是 2 和 31。所有一位数字都是回文,因此您需要检查 2 到 9 中的每一个。剩下的方式您只需要考虑 11 和 22,因为它们是唯一的两位数范围内的回文。你究竟是如何生成那些我不太清楚的。可能你只需要看33就可以确定它越界了。

推广到三位数、四位数等,将是一个单独的挑战,但我确信可以设计出一些非常优化的解决方案。

即使检查回文很方便,将数字作为字符串处理也可能效率低下。看看你是否可以在 int 数学中进行检查或至少你的生成。

好吧,这个 运行 只用了 13 毫秒(没有打印)。但我知道它可以通过生成一阶回文来改进,按顺序开始。但我会远离任何基于字符串的解决方案。

for (int i = 1; i < 100000; i++) {
    if (isPalindrome(i)) { 
        int k = i*i;
        if (isPalindrome(k)) {
           System.out.println(k);
        }
    }
}
        
public static boolean isPalindrome(int v) {
    int k = 0;
    int save = v;
    while (v > 0) {
        int d = v%10;
        k = k*10 +d;
        v/=10;
    }
    return k == save;
}

我认为你只需要一个 for 循环(除了将在该循环内的回文检查)从左到右的 sqrt。

    for(long i = L; i<Math.sqrt(R) ; i++){
      if(isPalidrome(i) && isPalindrom(i*i)){ans++;}

}

不知道我是否理解你的问题

终于找到了回文生成器的另一个优化
我使用与 isPalindrome:

相同的算法
long j = 0L;
long temp = i;

while (temp > 0L) {
    j = (10L * j) + (temp % 10L);
    temp /= 10L;
}

Math.floor(Math.log10(i)) + 1) 给出数字 class(位数)。
方法是:

public int superpalindromesInRange3(String left, String right) {

    // StringBuilder str = new StringBuilder();

    int ans = 0;
    long L = Long.parseLong(left);
    long R = Long.parseLong(right);

    // Odd palindrome 1234321
    for (long i = 1L; i < Long.MAX_VALUE; i++) {
        long p = i;
        if (i > 9) {

            long j = 0L;
            long temp = i / 10L;

            while (temp > 0L) {
                j = (10L * j) + (temp % 10L);
                temp /= 10L;
            }

            p = (long)(i * Math.pow(10, Math.floor(Math.log10(i / 10L)) + 1) + j);
        }
        long p_square = p * p;
        if (p_square > R)
            break;
        if (p_square >= L && isPalindrome(p_square))
            ans++;
    }

    // Even palindrome 12344321
    for (int i = 1; i < Integer.MAX_VALUE; i++) {

        long j = 0L;
        long temp = i;

        while (temp > 0L) {
            j = (10L * j) + (temp % 10L);
            temp /= 10L;
        }

        long p = (long)(i * Math.pow(10, Math.floor(Math.log10(i)) + 1) + j);

        long p_square = p * p;
        if (p_square > R)
            break;
        if (p_square >= L && isPalindrome(p_square))
            ans++;
    }
    return ans;
}

结果比使用 StringBuilder.

构造回文结构快两倍