web-dev-qa-db-ja.com

数字列の次の回文を見つけるためのより良いアルゴリズム

まず、ここに問題があります:

正の整数は、左から右および右から左に読み取ったときに10進法での表現が同じである場合、回文と呼ばれます。 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]反復でオフセットを確実にインクリメントできると思いました。私の変更の確認または提案をいただければ幸いです。また、質問を明確にする必要があるかどうかもお知らせください。

15
Mead3000

これはたくさんのコードのようです。非常に素朴なアプローチをもう試しましたか?何かが回文であるかどうかを確認することは、実際には非常に簡単です。

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")の10進表現を見つけます。
  2. それを左半分と右半分に分割します( "21"、 "33");
  3. 左半分の最後の桁と右半分の最初の桁を比較します。
    a。右がより大きい左の場合、左をインクリメントして停止します。 ( "22")
    b。右が未満左の場合は、停止します。
    c。右が等しい左の場合、最後から2番目の数字を左に、2番目の数字を右に(以下同様)、手順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

これは、説明したアルゴリズムに少し似ているように見えますが、内側の数字から始まり、外側に移動します。

39
Mark Peters

さて、私は一定の次数の解を持っています(少なくとも次数k、ここでkは数の桁数です)

N = 17208と仮定していくつかの例を見てみましょう

数値を中央から2つの部分に分割し、重要度の高い部分を重要度の低い部分に可逆的に書き込みます。つまり、そのように生成された数があなたのnより大きい場合は17271、それはあなたの回文です。中心数(ピボット)を増やすだけではない場合、つまり、17371を取得します

他の例

n = 17286 palidrome-attempt = 17271(n未満であるため、ピボットをインクリメントします。この場合は2)、palidrome = 17371

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

n = 458322回文= 458854

ここで、n = 1219901 palidrome1 = 1219121ピボットをインクリメントすると、ここで私の番号が小さくなると仮定します。したがって、ピボットに隣接する番号もインクリメントします。1220221

このロジックは拡張できます

9
Raks

必要な操作が1つの単純な追加だけである場合、個々の数字をいじる理由はありません。次のコードは 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"));
    }
}
8
Roland Illig

次のコードは、番号の次のPalandrome番号を検索します-

public class TestNextPalindrome {

    public static void main(String[] args) {
        int number1 = 45312;
        int number2 = 12345;
        int number3 = 12945;
        int number4 = 4531;
        int number5 = 1459;
        int number6 = 1997;
        System.out.print("For the number " + number1);
        getNextPalindrome(number1);
        System.out.print("For the number " + number2);
        getNextPalindrome(number2);
        System.out.print("For the number " + number3);
        getNextPalindrome(number3);
        System.out.print("For the number " + number4);
        getNextPalindrome(number4);
        System.out.print("For the number " + number5);
        getNextPalindrome(number5);
        System.out.print("For the number " + number6);
        getNextPalindrome(number6);
    }

    private static void getNextPalindrome(int number) {
        if (isSizeEven(number)) {

            getNextPalindromeForEvenLengthNumbers(number);
        }
        else {
            getNextPalindromeForOddLengthNumbers(number);
        }

    }

    private static boolean isSizeEven(int number) {
        if (String.valueOf(number).length() % 2 == 0)
            return true;
        return false;
    }

    private static void getNextPalindromeForEvenLengthNumbers(int number) {
        StringBuilder testPalindromeString = new StringBuilder();
        testPalindromeString.append(number);

        StringBuilder convertTopalindrome = new StringBuilder();
        convertTopalindrome.append(testPalindromeString.substring(0, testPalindromeString.length() / 2));

        convertTopalindrome.append(testPalindromeString.delete(testPalindromeString.length() / 2,
            testPalindromeString.length()).reverse());

        //if the palindrome is greater than the original number
        if (Integer.parseInt(convertTopalindrome.toString()) > number) {
            System.out.println(" the next palindrome is " + convertTopalindrome);
        }
        else {
            //get the middle elements in case of even numbers
            String middleElements =
                convertTopalindrome.substring(convertTopalindrome.length() / 2 - 1,
                    convertTopalindrome.length() / 2 + 1);
            int middleElementsInt = Integer.valueOf(middleElements);
            //we are going to increment the middle elements by 1 so check if after this the value is not greater than 99.
            if (middleElementsInt + 11 < 99) {
                convertTopalindrome.replace(convertTopalindrome.length() / 2 - 1,
                    convertTopalindrome.length() / 2 + 1, String.valueOf(middleElementsInt + 11));
                System.out.println(" the next palindrome is " + convertTopalindrome);
            }
            else {
                String numberTillMiddleElement =
                    convertTopalindrome.substring(0, convertTopalindrome.length() / 2 + 1);
                int numberTillMiddleElementInt = Integer.valueOf(numberTillMiddleElement);
                convertTopalindrome.replace(0, convertTopalindrome.length() / 2 + 1,
                    String.valueOf(numberTillMiddleElementInt + 1));
                getNextPalindrome(Integer.valueOf(convertTopalindrome.toString()));
            }
        }
    }

    private static void getNextPalindromeForOddLengthNumbers(int number) {

        StringBuilder testPalindromeString = new StringBuilder();
        testPalindromeString.append(number);

        StringBuilder convertTopalindrome = new StringBuilder();
        convertTopalindrome.append(testPalindromeString.substring(0, testPalindromeString.length() / 2 + 1));

        convertTopalindrome.append(testPalindromeString.delete(testPalindromeString.length() / 2,
            testPalindromeString.length()).reverse());

        //if the palindrome is greater than the original number
        if (Integer.parseInt(convertTopalindrome.toString()) > number) {
            System.out.println(" the next palindrome is " + convertTopalindrome);
        }
        else {

            char middleElement = convertTopalindrome.charAt(convertTopalindrome.length() / 2);
            int middleElementInt = Character.getNumericValue(middleElement);
            //we are going to increment the middle element by 1 so check if after this the value is not greater than 9.
            if (middleElementInt < 9) {
                convertTopalindrome.replace(convertTopalindrome.length() / 2,
                    convertTopalindrome.length() / 2 + 1, String.valueOf(middleElementInt + 1));
                System.out.println(" the next palindrome is " + convertTopalindrome);
            }
            else {
                String numberTillMiddleElement =
                    convertTopalindrome.substring(0, convertTopalindrome.length() / 2 + 1);
                int numberTillMiddleElementInt = Integer.valueOf(numberTillMiddleElement);
                convertTopalindrome.replace(0, convertTopalindrome.length() / 2 + 1,
                    String.valueOf(numberTillMiddleElementInt + 1));
                getNextPalindrome(Integer.valueOf(convertTopalindrome.toString()));
            }

        }

    }

}

コードの説明はここにあります- Javaを使用して次の回文を見つける

2
Rameez

これがJavaでの私のコードです。全体のアイデアはここからです http://www.geeksforgeeks.org/given-a-number-find-next-smallest-palindrome-larger-than-this-number/

java.util.Scannerをインポートします。

パブリッククラスメイン{

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

}

1
uberchilly
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);
    }



}
1

これを試して

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;    
}
0
Eric Kim