17

首先是问题所在:

如果一个正整数在十进制系统中的表示在从左到右和从右到左读取时相同,则称为回文。对于给定的不超过 1000000 位的正整数 K,将大于 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
}

最后我的解释和问题。

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.

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

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

4

10 回答 10

44

这似乎是很多代码。您是否尝试过一种非常幼稚的方法?检查某事物是否是回文实际上非常简单。

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

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

private int nextLargestPalindrome(int fromNumber) {
    for ( int i = fromNumber + 1; ; i++ ) {
        if ( isPalindrome( i ) ) {
            return i;
        }
    }
}

现在,如果这还不够快,您可以将其用作参考实现并致力于降低算法复杂性。

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

  1. 查找输入数字(“2133”)的十进制表示。
  2. 将其拆分为左半边和右半边(“21”,“33”);
  3. 比较左半部分的最后一位数字和右半部分的第一位数字。
    一种。如果右侧大于左侧,则增加左侧并停止。
    (“22”)如果右侧小于左侧,则停止。
    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

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

于 2011-10-28T21:13:29.543 回答
18

当唯一需要的操作是一个简单的加法时,没有理由摆弄单个数字。以下代码基于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"));
    }
}
于 2017-09-14T08:11:45.327 回答
14

好吧,我有恒定的顺序解决方案(至少 k 顺序,其中 k 是数字中的位数)

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

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

其他例子

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

n=5684 回文1=5665 回文=5775

n=458322 回文=458854

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

这个逻辑可以扩展

于 2011-11-18T19:10:05.530 回答
1

这是我在java中的代码。整个想法来自这里

import java.util.Scanner;

public class Main {

    public static void main(String[] args) {

        Scanner sc = new Scanner(System.in);
        System.out.println("Enter number of tests: ");
        int t = sc.nextInt();

        for (int i = 0; i < t; i++) {
            System.out.println("Enter number: ");
            String numberToProcess = sc.next(); // ne proveravam dal su brojevi
            nextSmallestPalindrom(numberToProcess);
        }
    }

    private static void nextSmallestPalindrom(String numberToProcess) {
        

        int i, j;

        int length = numberToProcess.length();
        int[] numberAsIntArray = new int[length];
        for (int k = 0; k < length; k++)
            numberAsIntArray[k] = Integer.parseInt(String
                    .valueOf(numberToProcess.charAt(k)));

        numberToProcess = null;

        boolean all9 = true;
        for (int k = 0; k < length; k++) {
            if (numberAsIntArray[k] != 9) {
                all9 = false;
                break;
            }
        }
        // case 1, sve 9ke
        if (all9) {
            whenAll9(length);
            return;
        }

        int mid = length / 2;
        if (length % 2 == 0) {
            i = mid - 1;
            j = mid;
        } else {
            i = mid - 1;
            j = mid + 1;
        }
        
        while (i >= 0 && numberAsIntArray[i] == numberAsIntArray[j]) {
            i--;
            j++;
        }
        // case 2 already polindrom
        if (i == -1) {
            if (length % 2 == 0) {
                i = mid - 1;
                j = mid;
            } else {
                i = mid;
                j = i;
            }
            addOneToMiddleWithCarry(numberAsIntArray, i, j, true);

        } else {
            // case 3 not polindrom
            if (numberAsIntArray[i] > numberAsIntArray[j]) { // 3.1)
                
                while (i >= 0) {
                    numberAsIntArray[j] = numberAsIntArray[i];
                    i--;
                    j++;
                }
                for (int k = 0; k < numberAsIntArray.length; k++)
                    System.out.print(numberAsIntArray[k]);
                System.out.println();
            } else { // 3.2 like case 2
                if (length % 2 == 0) {
                    i = mid - 1;
                    j = mid;
                } else {
                    i = mid;
                    j = i;
                }
                addOneToMiddleWithCarry(numberAsIntArray, i, j, false);
            }
        }
    }

    private static void whenAll9(int length) {
        
        for (int i = 0; i <= length; i++) {
            if (i == 0 || i == length)
                System.out.print('1');
            else
                System.out.print('0');
        }
    }

    private static void addOneToMiddleWithCarry(int[] numberAsIntArray, int i,
            int j, boolean palindrom) {
        numberAsIntArray[i]++;
        numberAsIntArray[j] = numberAsIntArray[i];
        while (numberAsIntArray[i] == 10) {
            numberAsIntArray[i] = 0;
            numberAsIntArray[j] = numberAsIntArray[i];
            i--;
            j++;
            numberAsIntArray[i]++;
            numberAsIntArray[j] = numberAsIntArray[i];
        }
        
        if (!palindrom)
            while (i >= 0) {
                numberAsIntArray[j] = numberAsIntArray[i];
                i--;
                j++;
            }
        
        for (int k = 0; k < numberAsIntArray.length; k++)
            System.out.print(numberAsIntArray[k]);
        System.out.println();
    }

}
于 2014-03-30T15:38:47.627 回答
1
public class NextPalindrome 
{   
    int rev, temp;
    int printNextPalindrome(int n) 
    {
        int num = n;
        for (int i = num+1; i >= num; i++) 
        {
            temp = i;
            rev = 0;
            while (temp != 0) 
            {
                int remainder = temp % 10;
                rev = rev * 10 + remainder;
                temp = temp / 10;
            }
            if (rev == i) 
            {
                break;
            }
        }
        return rev;
    }
    public static void main(String args[]) 
    {
        NextPalindrome np = new NextPalindrome();
        int nxtpalin = np.printNextPalindrome(11);
        System.out.println(nxtpalin);
    }



}
于 2015-01-21T09:45:06.160 回答
0

试试这个

public static String genNextPalin(String base){
    //check if it is 1 digit
    if(base.length()==1){
        if(Integer.parseInt(base)==9)
            return "11";
        else
            return (Integer.parseInt(base)+1)+"";
    }
    boolean check = true;
    //check if it is all 9s
    for(char a: base.toCharArray()){
        if(a!='9')
            check = false;
    }
    if(check){
        String num = "1";
        for(int i=0; i<base.length()-1; i++)
            num+="0";
        num+="1";
        return num;
    }

    boolean isBasePalin = isPalindrome(base);
    int mid = base.length()/2;
    if(isBasePalin){
        //if base is palin and it is odd increase mid and return
        if(base.length()%2==1){
            BigInteger leftHalf = new BigInteger(base.substring(0,mid+1));
            String newLeftHalf = leftHalf.add(BigInteger.ONE).toString();
            String newPalin = genPalin2(newLeftHalf.substring(0,mid),newLeftHalf.charAt(mid));
            return newPalin;
        }
        else{
            BigInteger leftHalf = new BigInteger(base.substring(0,mid));
            String newLeftHalf = leftHalf.add(BigInteger.ONE).toString();
            String newPalin = genPalin(newLeftHalf.substring(0,mid));
            return newPalin;
        }
    }
    else{
        if(base.length()%2==1){
            BigInteger leftHalf = new BigInteger(base.substring(0,mid));
            BigInteger rightHalf = new BigInteger(reverse(base.substring(mid+1,base.length())));

            //check if leftHalf is greater than right half
            if(leftHalf.compareTo(rightHalf)==1){
                String newPalin = genPalin2(base.substring(0,mid),base.charAt(mid));
                return newPalin;
            }
            else{
                BigInteger leftHalfMid = new BigInteger(base.substring(0,mid+1));
                String newLeftHalfMid = leftHalfMid.add(BigInteger.ONE).toString();
                String newPalin = genPalin2(newLeftHalfMid.substring(0,mid),newLeftHalfMid.charAt(mid));
                return newPalin;
            }
        }
        else{
            BigInteger leftHalf = new BigInteger(base.substring(0,mid));
            BigInteger rightHalf = new BigInteger(reverse(base.substring(mid,base.length())));

            //check if leftHalf is greater than right half
            if(leftHalf.compareTo(rightHalf)==1){
                return genPalin(base.substring(0,mid));
            }
            else{
                BigInteger leftHalfMid = new BigInteger(base.substring(0,mid));
                String newLeftHalfMid = leftHalfMid.add(BigInteger.ONE).toString(); 
                return genPalin(newLeftHalfMid);
            }
        }
    }
}

public static String genPalin(String base){
    return base + new StringBuffer(base).reverse().toString();
}
public static String genPalin2(String base, char middle){
    return base + middle +new StringBuffer(base).reverse().toString();
}

public static String reverse(String in){
    return new StringBuffer(in).reverse().toString();
}

static boolean isPalindrome(String str) {    
    int n = str.length();
    for( int i = 0; i < n/2; i++ )
        if (str.charAt(i) != str.charAt(n-i-1)) 
            return false;
    return true;    
}
于 2013-04-13T04:40:11.233 回答
-1

嗨这是另一个使用python的简单算法,

  def is_palindrome(n):
      if len(n) <= 1:
          return False
      else:
          m = len(n)/2
          for i in range(m):
              j = i + 1
              if n[i] != n[-j]:
                  return False
          return True

  def next_palindrome(n):
      if not n:
          return False
      else:
          if is_palindrome(n) is True:
              return n
          else:
             return next_palindrome(str(int(n)+1))

  print next_palindrome('1000010')
于 2013-12-03T17:06:48.687 回答
-1

我已经写了注释来阐明这个 python 代码中每个步骤在做什么。

需要考虑的一件事是输入可能非常大,我们不能简单地对其执行整数运算。因此,将输入作为字符串然后对其进行操作会容易得多。

tests = int(input())
results = []
for i in range(0, tests):
    pal = input().strip()
    palen = len(pal)
    mid = int(palen/2)
    if palen % 2 != 0:
        if mid == 0: # if the number is of single digit e.g. next palindrome for 5 is 6 
            ipal = int(pal)
            if ipal < 9:
                results.append(int(pal) + 1)
            else:
                results.append(11) # for 9 next palindrome will be 11
        else:
            pal = list(pal)
            pl = l = mid - 1
            pr = r = mid + 1
            flag = 'n' # represents left and right half of input string are same
            while pl >= 0:
                if pal[pl] > pal[pr]:
                    flag = 'r' # 123483489 in this case pal[pl] = 4 and pal[pr] = 3 so we just need to copy left half in right half
                    break      # 123484321 will be the answer
                elif pal[pl] < pal[pr]:
                    flag = 'm' # 123487489 in this case pal[pl] = 4 and pal[pr] = 9 so copying left half in right half will make number smaller
                    break # in this case we need to take left half increment by 1 and the copy in right half 123494321 will be the anwere
                else:
                    pl = pl -1
                    pr = pr + 1
            if flag == 'm' or flag == 'n': # increment left half by one and copy in right half
                if pal[mid] != '9': # if mid element is < 9 the we can simply increment the mid number only and copy left in right half
                        pal[mid] = str(int(pal[mid]) + 1)
                        while r < palen:
                            pal[r] = pal[l]
                            r = r + 1
                            l = l - 1
                        results.append(''.join(pal))
                else: # if mid element is 9 this will effect entire left half because of carry
                    pal[mid] = '0' # we need to take care of large inputs so we can not just directly add 1 in left half
                    pl = l
                    while pal[l] == '9':
                        pal[l] = '0'
                        l = l - 1
                    if l >= 0:
                        pal[l] = str(int(pal[l]) + 1)
                    while r < palen:
                        pal[r] = pal[pl]
                        r = r + 1
                        pl = pl - 1
                    if l < 0:
                        pal[0] = '1'
                        pal[palen - 1] = '01'
                    results.append(''.join(pal))
            else:
                while r < palen: # when flag is 'r'
                    pal[r] = pal[l]
                    r = r + 1
                    l = l - 1
                results.append(''.join(pal))
    else: # even length almost similar concept here with flags having similar significance as in case of odd length input
        pal = list(pal)
        pr = r = mid
        pl = l = mid - 1
        flag = 'n'
        while pl >= 0:
            if pal[pl] > pal[pr]:
                flag = 'r'
                break
            elif pal[pl] < pal[pr]:
                flag = 'm'
                break
            else:
                pl = pl -1
                pr = pr + 1
        if flag == 'r':
            while r < palen:
                    pal[r] = pal[l]
                    r = r + 1
                    l = l - 1
            results.append(''.join(pal))
        else:
            if pal[l] != '9':
                pal[l] = str(int(pal[l]) + 1)
                while r < palen:
                    pal[r] = pal[l]
                    r = r + 1
                    l = l - 1
                results.append(''.join(pal))
            else:
                pal[mid] = '0'
                pl = l
                while pal[l] == '9':
                    pal[l] = '0'
                    l = l - 1
                if l >= 0:
                    pal[l] = str(int(pal[l]) + 1)
                while r < palen:
                    pal[r] = pal[pl]
                    r = r + 1
                    pl = pl - 1
                if l < 0:
                    pal[0] = '1'
                    pal[palen - 1] = '01'
                results.append(''.join(pal))

for xx in results:
    print(xx) 
于 2016-10-30T12:59:55.727 回答
-1

我们可以像下面这样轻松地找到下一个回文。

private void findNextPalindrom(int i) {
    i++;
    while (!checkPalindrom(i)) {
        i++;
    }
    Log.e(TAG, "findNextPalindrom:next palindrom is===" + i);
}


private boolean checkPalindrom(int num) {
    int temp = num;
    int rev = 0;
    while (num > 0) {
        int rem = num % 10;
        rev = rev * 10 + rem;
        num = num / 10;
    }
    return temp == rev;
}
于 2020-11-16T06:12:42.367 回答
-2

简单代码和测试输出:

class NextPalin
{
public static void main( String[] args )
{
    try {
        int[] a = {2, 23, 88, 234, 432, 464, 7887, 7657, 34567, 99874, 7779222, 2569981, 3346990, 229999, 2299999 };
        for( int i=0; i<a.length; i++)
        {
            int add = findNextPalin(a[i]);
            System.out.println( a[i] + "  +  "  + add +  "  = "  + (a[i]+add)  );
        }
    }
    catch( Exception e ){}
}

static int findNextPalin( int a ) throws Exception
{
    if( a < 0 ) throw new Exception();
    if( a < 10 ) return a;

    int count = 0, reverse = 0, temp = a;
    while( temp > 0 ){
        reverse = reverse*10 + temp%10;
        count++;
        temp /= 10;
    }

    //compare 'half' value
    int halfcount = count/2;
    int base = (int)Math.pow(10, halfcount );
    int reverseHalfValue = reverse % base;
    int currentHalfValue = a % base;

    if( reverseHalfValue == currentHalfValue ) return 0;
    if( reverseHalfValue > currentHalfValue )  return  (reverseHalfValue - currentHalfValue);

    if(  (((a-currentHalfValue)/base)%10) == 9 ){
        //cases like 12945 or 1995
        int newValue = a-currentHalfValue + base*10;
        int diff = findNextPalin(newValue);
        return base*10 - currentHalfValue + diff;
    }
    else{
        return (base - currentHalfValue + reverseHalfValue );
    }
}
}

$ java NextPalin
2  +  2  = 4
23  +  9  = 32
88  +  0  = 88
234  +  8  = 242
432  +  2  = 434
464  +  0  = 464
7887  +  0  = 7887
7657  +  10  = 7667
34567  +  76  = 34643
99874  +  25  = 99899
7779222  +  555  = 7779777
2569981  +  9771  = 2579752
3346990  +  443  = 3347433
229999  +  9933  = 239932
2299999  +  9033  = 2309032
于 2013-06-18T04:23:52.037 回答