Лучший алгоритм для поиска следующего палиндрома числовой строки
Во-первых, здесь проблема:
Положительное целое число называется палиндром, если его представление в десятичной системе одинаково при чтении слева направо и справа налево. Для заданного положительного целого числа K не более 1000000 цифр напишите значение наименьшего палиндрома, большего, чем K для вывода. Номера всегда отображаются без начальных нhive.
Вход: первая строка содержит целое число t, количество тестовых примеров. Целые числа K задаются в следующих t строках.
- Как вы печатаете EXACT значение числа с плавающей запятой?
- Как найти дублирующий элемент в массиве перетасованных последовательных целых чисел?
- Как вычислить число 3D Morton (чередуйте биты 3 ints)
- Как найти, какие элементы находятся в сумке, используя алгоритм Knapsack Algorithm ?
- C ++: округление до ближайшего кратного числа
Выход: для каждого К выведите наименьший палиндром больше, чем 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 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 ie 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 eg 78849887 we set the 9 --> 4 and increase 4 --> 5, so we must cater for this.
Проблема заключается в том, что spoj.pl представляет систему онлайн-судей. Мой код работает для всего теста, который может быть предоставлен, но когда я его отправлю, у меня превышен лимит времени, и мой ответ не принят.
У кого-нибудь есть предложения относительно того, как я могу улучшить свой алгоритм. При написании этого вопроса я думал, что вместо цикла while (offset == 0 && offsetUpdated) я мог бы использовать логическое значение, чтобы убедиться, что я увеличиваю смещение на следующей [i] итерации. Подтверждение моего изменения или любого предложения было бы оценено, также сообщите мне, если мне нужно сделать мой вопрос более ясным.
- Массив удаляет повторяющиеся элементы
- Каков наилучший способ проверить силу пароля?
- Как сравнить две фигуры?
- Сколько чисел ниже N являются взаимными ошибками до N?
- Определение пересечения двух сегментов линии?
- Создать последовательность случайных чисел без повторений
- Алгоритм для обнаружения пересечения двух прямоугольников?
- Существует ли эффективный алгоритм для создания двумерного вогнутого корпуса?
Это похоже на много кода. Вы пробовали очень наивный подход? Проверка того, что-то является палиндром, на самом деле очень проста.
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; } } }
Теперь, если это недостаточно быстро, вы можете использовать его в качестве эталонной реализации и работать над уменьшением алгоритмической сложности.
На самом деле должно быть постоянное время (ну, линейно по количеству цифр ввода), чтобы найти следующий самый большой палиндром. Я дам алгоритм, предполагающий, что число равно четному числу цифр (но может быть увеличено до нечетного числа цифр).
- Найдите десятичное представление входного номера («2133»).
- Разделите его на левую половину и правую половину («21», «33»);
- Сравните последнюю цифру в левой половине и первую цифру в правой половине.
а. Если право больше левого, увеличивайте левый и стоп. ( “22”)
б. Если право меньше левого, остановитесь.
с. Если право равно левому, повторите шаг 3 со второй последней цифрой в левой и второй цифрой справа (и так далее). - Возьмите левую половину и добавьте левую половину назад. Это ваш следующий самый большой палиндром. ( “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
Это похоже на алгоритм, который вы описали, но он начинается с внутренних цифр и перемещается на внешний.
Ну, у меня есть решение постоянного порядка (по крайней мере порядка k, где k – число цифр в числе)
Давайте возьмем некоторые примеры, предположим, что n = 17208
разделите число на две части от середины и обратимо напишите наиболее значительную часть на менее значительную. т. е. 17271, если такое сгенерированное число больше вашего n, это ваш палиндром, если не просто увеличить число центров (ось поворота), то есть вы получите 17371
другие примеры
n = 17286 palidrome-попытка = 17271 (так как в этом случае он меньше n приращений, в этом случае 2), так что palidrome = 17371
n = 5684 palidrome1 = 5665 palidrome = 5775
n = 458322 palindrome = 458854
теперь предположим, что n = 1219901 palidrome1 = 1219121, увеличивая ось вращения, делает мой номер здесь меньшим, поэтому увеличивайте число смежных опорных элементов 1220221
и эта логика может быть расширена
Нет никаких причин, чтобы играть с отдельными цифрами, когда единственная необходимая операция – одно простое дополнение. Следующий код основан на ответе Ракса .
Код подчеркивает простоту над скоростью выполнения, преднамеренно.
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")); } }
Следующий код находит следующий номер 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
Вот мой код в java. Вся идея отсюда: http://www.geeksforgeeks.org/given-a-number-find-next-smallest-palindrome-larger-than-this-number/
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(); }
}
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); } }
Попробуй это
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
HI Вот еще один простой алгоритм, использующий 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')
Я написал комментарии, чтобы уточнить, что делает каждый шаг в этом коде 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 eg 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)
Простые коды и тестовый выход:
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 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