找到数字串的下一个回文的更好算法

Mea*_*000 14 java algorithm palindrome

首先是问题所在:

如果正整数在从左到右和从右到左读取时在十进制系统中的表示相同,则称为回文.对于给定的正整数K不超过1000000个数字,写入大于K的最小回文值输出.始终显示数字而不带前导零.

输入:第一行包含整数t,测试用例数.整数K在下一个t行中给出.

输出:对于每个K,输出大于K的最小回文.示例

输入:

2

808

2133

输出:

818

2222

其次这是我的代码:

// I know it is bad practice to not cater for erroneous input,
// however for the purpose of the execise it is omitted
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.Scanner;
import java.lang.Exception;
import java.math.BigInteger;

public class Main
{    
    public static void main(String [] args){   
        try{
            Main instance = new Main(); // create an instance to access non-static
                                        // variables

            // Use java.util.Scanner to scan the get the input and initialise the
            // variable
            Scanner sc=null;

            BufferedReader r = new BufferedReader(new InputStreamReader(System.in));

            String input = "";

            int numberOfTests = 0;

            String k; // declare any other variables here

            if((input = r.readLine()) != null){
                sc = new Scanner(input);
                numberOfTests = sc.nextInt();
            }

            for (int i = 0; i < numberOfTests; i++){
                if((input = r.readLine()) != null){
                    sc = new Scanner(input);
                    k=sc.next(); // initialise the remainder of the variables sc.next()
                    instance.palindrome(k);
                } //if
            }// for
        }// try

        catch (Exception e)
        {
            e.printStackTrace();
        }
    }// main

    public void palindrome(String number){

        StringBuffer theNumber = new StringBuffer(number);
        int length = theNumber.length();
        int left, right, leftPos, rightPos;
        // if incresing a value to more than 9 the value to left (offset) need incrementing
        int offset, offsetPos;
        boolean offsetUpdated;
        // To update the string with new values
        String insert;
        boolean hasAltered = false;

        for(int i = 0; i < length/2; i++){
            leftPos = i; 
            rightPos = (length-1) - i;
            offsetPos = rightPos -1; offsetUpdated = false;

            // set values at opposite indices and offset
            left = Integer.parseInt(String.valueOf(theNumber.charAt(leftPos)));
            right = Integer.parseInt(String.valueOf(theNumber.charAt(rightPos)));
            offset = Integer.parseInt(String.valueOf(theNumber.charAt(offsetPos)));

            if(left != right){
                // if r > l then offest needs updating
                if(right > left){
                    // update and replace
                    right = left;
                    insert = Integer.toString(right);

                    theNumber.replace(rightPos, rightPos + 1, insert);

                    offset++; if (offset == 10) offset = 0;
                    insert = Integer.toString(offset);

                    theNumber.replace(offsetPos, offsetPos + 1, insert);
                    offsetUpdated = true;

                    // then we need to update the value to left again
                    while (offset == 0 && offsetUpdated){ 
                        offsetPos--;
                        offset =
                            Integer.parseInt(String.valueOf(theNumber.charAt(offsetPos)));
                        offset++; if (offset == 10) offset = 0;
                        // replace
                        insert = Integer.toString(offset);
                        theNumber.replace(offsetPos, offsetPos + 1, insert);
                    }
                    // finally incase right and offset are the two middle values
                    left = Integer.parseInt(String.valueOf(theNumber.charAt(leftPos)));
                    if (right != left){
                        right = left;
                        insert = Integer.toString(right);
                        theNumber.replace(rightPos, rightPos + 1, insert);
                    }
                }// if r > l
                else
                    // update and replace
                    right = left;
                    insert = Integer.toString(right);
                    theNumber.replace(rightPos, rightPos + 1, insert);           
            }// if l != r
        }// for i
        System.out.println(theNumber.toString());
    }// palindrome
}
Run Code Online (Sandbox Code Playgroud)

最后我的解释和问题.

My code compares either end and then moves in
    if left and right are not equal
        if right is greater than left
            (increasing right past 9 should increase the digit
             to its left i.e 09 ---- > 10) and continue to do
             so if require as for 89999, increasing the right
             most 9 makes the value 90000

             before updating my string we check that the right
             and left are equal, because in the middle e.g 78849887
             we set the 9 --> 4 and increase 4 --> 5, so we must cater for this.
Run Code Online (Sandbox Code Playgroud)

问题来自spoj.pl在线评判系统.我的代码适用于所有测试可以提供但是当我提交它时,我得到超出时间限制的错误,我的答案不被接受.

有没有人对如何改进我的算法有任何建议.在写这个问题时,我认为不是我的while(offset == 0 && offsetUpdated)循环,我可以使用布尔值来确保我在下一个[i]迭代中增加偏移量.确认我的chang或任何建议将不胜感激,如果我需要让我的问题更清楚,请告诉我.

Mar*_*ers 39

这似乎是很多代码.你尝试过一种非常天真的方法吗?检查某些东西是否是回文实际上非常简单.

private boolean isPalindrome(int possiblePalindrome) {
    String stringRepresentation = String.valueOf(possiblePalindrome);
    if ( stringRepresentation.equals(stringRepresentation.reverse()) ) {
       return true;
    }
}
Run Code Online (Sandbox Code Playgroud)

现在,这可能不是最高性能的代码,但它为您提供了一个非常简单的起点:

private int nextLargestPalindrome(int fromNumber) {
    for ( int i = fromNumber + 1; ; i++ ) {
        if ( isPalindrome( i ) ) {
            return i;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

现在,如果速度不够快,您可以将其用作参考实现,并努力降低算法的复杂性.

实际上应该有一个恒定时间(它是输入数字的线性)以找到下一个最大的回文.我将给出一个算法,假设该数字是偶数位数(但可以扩展为奇数位数).

  1. 找到输入数字的十进制表示("2133").
  2. 将它分成左半部分和右半部分("21","33");
  3. 比较左半部分的最后一位数字和右半部分的第一位数字.
    一个.如果右边大于左边,则向左递增并停止.("22")
    b.如果右边小于左边,则停止.
    C.如果右边等于左边,重复步骤3,左边倒数第二个,右边第二个数字(依此类推).
  4. 取左半边,然后将左半边反转.这是你的下一个最大的回文.( "2222")

适用于更复杂的数字:

1.    1234567887654322
2.    12345678   87654322
3.    12345678   87654322
             ^   ^         equal
3.    12345678   87654322
            ^     ^        equal
3.    12345678   87654322
           ^       ^       equal
3.    12345678   87654322
          ^         ^      equal
3.    12345678   87654322
         ^           ^     equal
3.    12345678   87654322
        ^             ^    equal
3.    12345678   87654322
       ^               ^   equal
3.    12345678   87654322
      ^                 ^  greater than, so increment the left

3.    12345679

4.    1234567997654321  answer
Run Code Online (Sandbox Code Playgroud)

这似乎与您描述的算法类似,但它从内部数字开始并移动到外部.

  • 你可以改进这个,如果你拆分整个字符串/字符特征,反转rhs子字符串并比较它们.如果rhs更大,则将lhs增加1.之后的结果是lhs ^ lhs_reversed.对于奇数#digits只是弄清楚中间字符是否必须递增并做明显的事情 (3认同)
  • 这个数字最多可以有1000000个数字,所以int是不可能的.使用你的算法我在下半场增加889个数字的数字应该对前半部分产生影响 (2认同)

Rak*_*aks 9

好吧,我有恒定的订单解决方案(至少为k阶,其中k是数字中的位数)

让我们举一些例子,假设n = 17208

将数字从中间分成两部分,并将最重要的部分可逆地写入不太重要的部分.即17271,如果这样生成的数字大于你的n它是你的回文,如果不只是增加中心数(枢轴),即,你得到17371

其他例子

n = 17286 palidrome-attempt = 17271(因为它小于n增量枢轴,在这种情况下为2)所以palidrome = 17371

n = 5684 palidrome1 = 5665 palidrome = 5775

n = 458322回文数= 458854

现在假设n = 1219901 palidrome1 = 1219121递增枢轴使得我的数字在这里变小所以增加邻近枢轴的数量也是1220221

这个逻辑可以扩展


Rol*_*lig 8

当唯一需要的操作是一个简单的添加时,没有理由摆弄个别数字.以下代码基于Raks的回答.

该代码有意识地强调了执行速度的简单性.

import static org.junit.Assert.assertEquals;

import java.math.BigInteger;
import org.junit.Test;

public class NextPalindromeTest {

    public static String nextPalindrome(String num) {
        int len = num.length();
        String left = num.substring(0, len / 2);
        String middle = num.substring(len / 2, len - len / 2);
        String right = num.substring(len - len / 2);

        if (right.compareTo(reverse(left)) < 0)
            return left + middle + reverse(left);

        String next = new BigInteger(left + middle).add(BigInteger.ONE).toString();
        return next.substring(0, left.length() + middle.length())
             + reverse(next).substring(middle.length());
    }

    private static String reverse(String s) {
        return new StringBuilder(s).reverse().toString();
    }

    @Test
    public void testNextPalindrome() {
        assertEquals("5", nextPalindrome("4"));
        assertEquals("11", nextPalindrome("9"));
        assertEquals("22", nextPalindrome("15"));
        assertEquals("101", nextPalindrome("99"));
        assertEquals("151", nextPalindrome("149"));
        assertEquals("123454321", nextPalindrome("123450000"));
        assertEquals("123464321", nextPalindrome("123454322"));
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 这是一段如此美妙的代码。想知道为什么这没有得到赞成票? (2认同)