Project Euler Problem 4: Largest Palindrome Product

The Problem

A palindromic number reads the same both ways.

The largest palindrome made from the product of two 2-digit numbers is \[ 9009 = 91 \times 99 \]

Find the largest palindrome made from the product of two 3-digit numbers.

My Initial Approach

The plan was straightforward: multiply all pairs of 3-digit numbers, dump the results into a vector, then traverse the vector to find the largest palindrome. Nothing exotic. Here is what I actually wrote:

int a, b = 100;
for (int x = 0; x < 1000; x++)
{
    int temp;
    temp = a * b;
    results.push_back(temp);
    a++;
    b++;
}

Three bugs. Let’s go through them.

Bug 1: Uninitialized Variable

int a, b = 100; // only b is initialized. a is garbage.

This is actually a basic mistake I did, I guess I haven’t paid enough attention while solving the question. The syntax int a, b = 100 does not initialize both variables to 100, it declares a uninitialized and sets b to 100. Reading from a before assigning it is undefined behavior: the program might crash, produce wrong output, or appear to work correctly depending on what happened to be in that memory location.

The fix is trivial:

int a = 100, b = 100;

Bug 2: Wrong Loop Structure

Even with a properly initialized, the loop is wrong. Incrementing both a and b together in lockstep only tests the diagonal:

100×100, 101×101, 102×102, ..., 1099×1099

That is not “all pairs of 3-digit numbers.” You need a nested loop to cover the full Cartesian product:

for (int a = 100; a <= 999; a++)
    for (int b = a; b <= 999; b++) // b starts at a to avoid duplicate pairs
        results.push_back(a * b);

Starting b at a rather than 100 halves the work by skipping symmetric duplicates — 100×200 and 200×100 produce the same product.

Bug 3: Unconditional Assignment

if (isPalindrome(i) == 1){
    highestPalindrome = i; // overwrites regardless of whether i is larger
}

This just sets highestPalindrome to whatever the last palindrome in the vector is, not the largest. You need an additional guard:

if (isPalindrome(i) && i > highestPalindrome)
    highestPalindrome = i;

The Vector

I kept the vector intentionally to preserve the structure of the original approach, but it is worth noting why it is unnecessary here. The vector stores roughly 500,000 integers for a single read-once traversal. You never need more than one product in memory at a time, you can check each product against the current maximum as you compute it and discard it immediately.

The reason to keep a vector would be if you needed the full list for further processing: sorting, multiple passes, statistical queries. Here you don’t, so it is overhead with no payoff.

Final Code

#include <vector>
#include <iostream>

bool isPalindrome(int num) {
    int original = num;
    int reversed = 0;
    while (num > 0) {
        int digit = num % 10;
        reversed = reversed * 10 + digit;
        num /= 10;
    }
    return original == reversed;
}

int main()
{
    std::vector<int> results;
 
    for (int a = 100; a <= 999; a++)
        for (int b = a; b <= 999; b++)
            results.push_back(a * b);
         
    int highestPalindrome = 0;
    for (auto i : results)
        if (isPalindrome(i) && i > highestPalindrome)
            highestPalindrome = i;
         
    std::cout << "Largest Palindrome Product: " << highestPalindrome << "\n";
    return 0;
}

The answer is 906609.

You can find the full code at my Github: https://github.com/AydoganArslantash/Project-Euler-Solutions/blob/main/large_palindrome.cpp