Эта задача из проекта Эйлера № 4. Я новичок в программировании и разбираюсь только в типах данных, переменных, циклах, массивах и функциях. если ответ окажется действительно сложным, пожалуйста, скажите мне, что искать.
Итак, проблема заключалась в следующем: число-палиндром читается одинаково в обоих направлениях. Самый большой палиндром, составленный из произведения двух двузначных чисел, равен 9009=91*99.
Найдите наибольший палиндром, составленный из произведения двух трёхзначных чисел.
Сложность этой задачи, по-видимому, проста, но это заняло у меня несколько дней. Исходная программа, которую я разработал, содержала некоторые синтаксические ошибки, поэтому я воспользовался помощьюchat-gpt.
#include <stdio.h>
#include <stdbool.h>
// palindrome checker
bool is_palindrome(int p) {
int original = p;
int reversed = 0;
int remainder;
// Reverse the digits
while (p > 0) {
remainder = p % 10;
reversed = reversed * 10 + remainder;
p = p / 10;
}
// Check if the original number is the same as the reversed number
//turns out I don't have to say if original == reversed , return true.
return original == reversed;
}
int main(void) {
int largest_palindrome = 0;
int factor1 = 0, factor2 = 0;
// Check products of all pairs of 3-digit numbers
for (int i = 10000; i <= 99999; i++) {
for (int j = 10000; j <= 99999; j++) {
int product = i * j;
if (is_palindrome(product) && product > largest_palindrome) {
largest_palindrome = product;
factor1 = i;
printf("Factor 1 : %d\n",i);//I wanted to see the patterns of the factors
factor2 = j;
printf("Factor 2 : %d\n",j);
printf(" product : %d\n",largest_palindrome);
}
}
}
printf("The largest palindrome made from the product of two 5-digit numbers is %d (%d * %d).\n", largest_palindrome, factor1, factor2);
return 0;
}*/
bool is_palindrome(int p) {
int original = p;
int reversed = 0;
int remainder;
while (p > 0) {
remainder = p % 10;
reversed = reversed * 10 + remainder;
p = p / 10;
}
return original == reversed;
}
int main(void) {
int largest_palindrome = 0;
int factor1 = 0, factor2 = 0;
//my genius idea
for (int i = 99999; i >= 10000; i--) {
for (int j =99999; j >= 10000; j--) {
int product = i * j;
// If the product is less than the largest palindrome yet, break loop
if (product <= largest_palindrome) {
break;
}
if (is_palindrome(product)) {
factor1 = i;
printf("Factor 1 : %d\n",i);
factor2 = j;
printf("Factor 2 : %d\n",j);
largest_palindrome = product;
printf(" product : %d\n",largest_palindrome);
}
}
}
printf("The largest palindrome made from the product of two 5-digit numbers is %d (%d * %d).\n", largest_palindrome, factor1, factor2);
return 0;
}
Первая программа дала правильный результат для трехзначных чисел: 906609(993*991). На онлайн-компиляторе ушло 45 мс. 4 цифры заняли 1 секунду или что-то в этом роде. 99000099 (9999*9901). Для 5 цифр это заняло минуту. 2147447412 (21516 * 99807) Кажется, один фактор намного меньше другого, мне это показалось несколько интересным.
9999999999 =9999800001. и 1000010000=100000000, поэтому проверка факторов от верхнего предела и переход к i--,j-- должны быть намного быстрее.
для второй программы результат 2126776212 (21397 * 99396). Это заняло меньше секунды, и это круто, но ответ не совпал. Проверив printf, я увидел, что он движется в правильном направлении: 2126776212 (21397 * 99396) на 3 палиндрома отстает от 2147447412 (21516 * 99807), что является результатом первого. для трех- и четырехзначных пар коэффициентов обе программы дают одинаковый результат.
Теперь я не знаю, правильный ли один из них или оба неправильные. Я не думаю, что смогу найти это с помощью онлайн-калькулятора.
Пожалуйста, скажите мне, что вы думаете. Спасибо.
А когда вы умножаете 5-значные числа, вы получаете 10-значные числа, которые, вероятно, будут слишком большими для int
, который обычно составляет 32 бита.
Я должен был прояснить это с самого начала: я смог сделать трехзначный номер, я немного поэкспериментировал, и пятизначный код вызвал путаницу.
Для десятизначных чисел нужно использовать long
вместо int
, а может даже long long
.
подожди, дай мне попробовать
Как отмечали другие, вы, вероятно, перегружены int
своими 10-значными продуктами, что ухудшает ваши результаты. Как для емкости, так и для производительности все ваши интегральные переменные должны быть unsigned long
.
Ваш подход во втором примере хорош, но есть также несколько оптимизаций, которые вы можете добавить, чтобы ускорить процесс:
#include <stdio.h>
static int is_palindrome(unsigned long p)
{
unsigned long reversed = 0;
unsigned long original = p;
while (p)
{
// (1)
unsigned long remainder = p % 10;
p /= 10;
reversed = (reversed * 10) + remainder;
}
return original == reversed;
}
int main()
{
unsigned long largest_palindrome = 0;
unsigned long factor1, factor2;
for (unsigned long i = 99999; i >= 10000; --i)
{
// (2)
for (unsigned long j = i; j >= 10000; --j)
{
unsigned long product = i * j;
// If the product is less than the largest palindrome yet, break loop
if (product <= largest_palindrome)
break;
if (is_palindrome(product))
{
largest_palindrome = product;
factor1 = i;
factor2 = j;
printf("\t%lu\t%lu\t%lu\n", factor1, factor2, product);
}
}
}
printf("largest = %lu\n", largest_palindrome);
return 0;
}
Изменение is_palindrome
делает операцию немного быстрее, поскольку ЦП вычисляет результат и остаток от деления в одной инструкции.
j
никогда не должно быть больше i
, потому что эта комбинация уже должна быть проверена.
Добавьте условие if (i < factor2) break;
после внутреннего цикла для большей оптимизации. т.е. для 6 цифр, когда вы добавляете это условие, вы значительно уменьшаете количество проводимых тестов в 10 раз.
Числа-палиндромы с четным количеством цифр обладают странным свойством: все они кратны 11. Поэтому, когда i
делится на 11, вам нужно будет проверить все возможные значения j
; но если i
нет, то вы хотите проверить только возможные значения j
, кратные 11. С двумя шестизначными коэффициентами это уменьшает количество итераций примерно с 206 миллионов до примерно 32 миллионов (эти результаты уже включают @ оптимизация Оньямбу)
У меня есть еще один вопрос. Вы сказали: «Как для емкости, так и для производительности все ваши целочисленные переменные должны иметь длину без знака». почему это? могу ли я просто записать самый большой тип данных для каждой программы, чтобы гарантировать, что у меня никогда не возникнет такая проблема? типа долго-долго? Возможно, глупый вопрос.
Если вам не нужны отрицательные числа, всегда используйте unsigned
. Процессоры выполняют беззнаковую арифметику, и точка. Целые числа со знаком, по сути, являются синтаксическим сахаром по сравнению с целыми числами без знака, и процессор имеет некоторую встроенную обработку битов для их поддержки, но при прочих равных условиях арифметика без знака более эффективна, чем арифметика со знаком. На любом современном 64-битном процессоре long
и long long
имеют одинаковый размер, или вы можете просто #include <stdint.h>
и использовать тип uint64_t
(который, скорее всего, имеет тип unsigned long
)
Я понимаю. Спасибо
int i = 10000; i <= 99999
Это пятизначные числа, а не трехзначные.