如何优化使用BigInteger操作执行时间的代码

时间:2015-03-18 16:29:45

标签: java algorithm biginteger palindrome

以下程序采用输入数k并生成大于k的回文。输入数字k可以是1000000位。

我使用java.math.BigInteger类使用jdk 1.6在Java中实现了上述程序。

以下是代码:

import java.math.BigInteger;

class Palindrome
{
    private BigInteger reverse(BigInteger inputNumber)
    {
        BigInteger reversedNumber = new BigInteger("0");        
        while(inputNumber.compareTo(BigInteger.ZERO) > 0)
        {
            reversedNumber = reversedNumber.multiply(BigInteger.TEN);
            reversedNumber = reversedNumber.abs().add(inputNumber.mod(BigInteger.TEN));
            inputNumber = inputNumber.divide(BigInteger.TEN);
        }
        return reversedNumber;
    }

    public BigInteger nextPalindrome(BigInteger inputNumber)
    {
        BigInteger i = new BigInteger(inputNumber.toString());        
        for(i=i.add(BigInteger.ONE);;i=i.add(BigInteger.ONE))
        {            
            if(i.equals(reverse(i)))
                return i;
        }
    }
}

public class NextPalindrome {
    public static void main(String args[]) throws Exception
    {
        java.util.Scanner input = new java.util.Scanner(System.in); 

        Palindrome p = new Palindrome();
        BigInteger inputNumber = input.nextBigInteger(); //To store 1000000 digit number
        System.out.println(p.nextPalindrome(inputNumber));
    }
}

该代码适用于以下输入: 输入:808,输出:818
输入:1311,输出:1331
输入:123456789,输出:123464321
但输入时:123456789123456789,未生成输出

如何针对更大的输入优化代码?

3 个答案:

答案 0 :(得分:0)

编写自己的自定义算法。不要像你那样使用BigInteger。你使用的当前算法:1)是直截了当,琐碎的,相当蛮力; 2)使用BigInteger可以在不使用它的情况下使用它。

答案 1 :(得分:0)

我假设问题是在输入后返回 next 回文。

这是一种有效的方法:

BigInteger转换为char[]。通过反映上半部分来更改char[]的后半部分。将结果转换为BigInteger。如果此BigInteger大于原始版本,请将其返回。否则,将char[]的第一个 half 转换为BigInteger,添加一个,转换回char[],反映它,转换回{{ 1}},并将其归还。

这是基本算法,但有两个可能的陷阱。 (1)您必须注意确保算法适用于偶数和奇数长度的字符串。 (2)你还必须特别注意数字以9s开头的情况(在这种情况下,结果的数字可能比原始数字多)。

祝你好运!

答案 2 :(得分:0)

我可能根本不会使用BigInteger,主要是因为这里没有涉及算术。数字是否为回文可以通过将数字转换为字符串,并将字符串与反向进行比较来完成。

所以,第一个选择是你写一个这样的方法:

private static boolean isPalindrome(String number) {
    return new StringBuilder(number).reverse().toString().equals(number);
}

从开始的每个BigInteger,将其转换为字符串,并调用此方法,直到你得到回文。

但是这种方法仍然很重,因为您将继续创建新的BigInteger对象(通过继续添加1)。因此,诀窍是,通过在结束索引处设置字符来转换给定数字(作为字符串),匹配相应起始索引的字符。

让我们考虑你的号码123456789。这个过程是这样的:

  1. start = 0end = str.length() - 1
  2. 如果end char大于start char,请将结束字符设置为start char。因此,在这种情况下,当前startChar为'1',endChar为'9'。因此,大于此数字的最小回文将'1'作为最后一个字符,因此我们将'9'替换为'1'。该数字变为: 12345678 1 。 (一个)。如果end char大于start char和end == start + 1,则只需将start char设置为end char并退出。

  3. 但是我们通过将最后一个索引设置为较低的值来减少数量。所以,让我们将end - 1索引增加1。数字 12345678 1 将更改为 - > 1234567的 9 1

  4. 启动++,结​​束 - 。重复步骤2和3,直到找到end索引处的字符小于start索引处的字符。
  5. 现在,在这个阶段我们的号码是:123464321
  6. 所以现在我们start > end。这里算法将停止。结果为123464321
  7. 但假设您的号码是:126456389,那么在第5步,您的号码将是: 12 6 456 4 21 (使用start = 2end = str.length() - 2

    继续第5步:

    • 一旦结束索引( 4 )小于起始索引( 6 )字符,请将结束索引字符设置为起始索引字符。在这里,数字变为: 12 6 456 6 21 。从第2步开始重复。

    一旦start > end条件到达,你就会将你的回文记录在字符串中。

    以下是上述算法的代码:

    public static String getNextPalindrome(String number) {
        char[] str = number.toCharArray();
    
        int front = 0;
        int back = str.length - 1;
    
        while (front < back) {
            if (str[back] > str[front]) {
              if (back == front + 1) {
                str[front] = str[back];
              } else {
                str[back] = str[front];
                str[back - 1] = (char) (str[back - 1] + 1);
              }
            } else if (str[back] < str[front]) {
              str[back] = str[front];
            }
            front++;
            back--;
        }
    
        return new String(str);
    }
    

    注意:上述算法尚未考虑数字已经是回文的情况。我会把它留给你(虽然这是一件小事)。