Project Euler / programming problems

I wanted to find a cool way to traverse palindromes only but I got stuck in the numbers so this is all I came up with. I wish I knew maths. I don’t even know what this relation is called when you have a pair of iterators and you increment one by 10^i and the other by 10^-i. And yes it would’ve been simpler to just traverse 999 down to 100 and then mirror it every iteration with string operations.

const traversePalindromes = (palindrome=999999, iter=1, multiplier=10) => { 
    console.log(
        palindrome - 
        iter * multiplier - 
        (
            (iter * multiplier 
               / Math.pow(10, Math.max(Math.floor(Math.log10(Math.abs(iter * multiplier))), 0))
            )
            * 100000
        ) 
        * Math.pow(10, -1 * Math.max(Math.floor(Math.log10(Math.abs(iter * multiplier))), 0))
    );
        
    multiplier <= 100000 ? traversePalindromes(palindrome, iter >= 9 ? 1 : iter+1, iter >= 9 ? multiplier * 10 : multiplier) : true 
};
traversePalindromes();
Brute forced it because my machine work faster than me figuring out the %100 %11 thing xD
const findPalindrome = () => {
  const allPalindrome = Array.from({ length: 900 }, (v, i) => {
    const number1 = 999 - i;
    return Array.from({ length: 900 }, (v, j) => {
      const number2 = 999 - j;
      return {
        number1,
        number2,
        product: number1 * number2,
      };
    });
  })
    .flat()
    .filter((obj) => isPalindrome(obj.product))
    .sort((a, b) => b.product - a.product);

  if (allPalindrome.length > 0) return allPalindrome[0];
  else return "No number satisfy condition";
};

const isPalindrome = (number) => {
  const numberAsString = `${number}`;
  const length = numberAsString.length;

  for (let i = 0; i < Math.floor(length / 2); i++) {
    if (numberAsString[i] != numberAsString[length - 1 - i]) return false;
  }
  return true;
};

console.log(JSON.stringify(findPalindrome()));

1 Like

Thought it would be kind of fun to visualize the “shave”. Using Python’s Pillow, I made images that represent the values that were iterated in some of the algorithms above. Really demonstrates how effective that %11 trick is!

images

key:

  • white=didn’t touch
  • pink=low-value touched non-palindromes
  • cyan=high-value touched non-palindromes
  • navy=palindromes



I didn’t try to translate the JS solutions to Python, but anyone feel free to mess with the script:

img = Image.new("RGB", (1000, 1000))

px = img.load()

# fill white
for i in range(1000):
    for j in range(1000):
        px[i, j] = (256, 256, 256)

def isPalindrome(i, j):
    s = str(i * j)
    return s == s[::-1]

def addPixel(i, j):
    val = i * j * 256 // 1000000
    if isPalindrome(i, j):
        px[i, j] = (0, 20, 128)
    else:
        px[i, j] = (256-val//2, val//2+128, 256)

# Your algorithm here
# Call addPixel(i, j) in the innermost loop

img.save('image_name.png', 'png')

Oh and I’ll add my own- after doing this I thought of my own way to cut down on loops. I wonder if anyone can guess what’s going on from the picture alone?

Solution for # 4, python

max_pal = 0
for i in range(999, 0, -1):
    if i * 999 < max_pal:
        break
    for j in range(999, i - 1, -1):
        addPixel(i, j)
        if i * j < max_pal:
            break
        if isPalindrome(i, j):
            max_pal = i * j
print("max", max_pal)
1 Like

I’ve some comments above that might help if interested

Just spoilered so people don’t have to read them :slight_smile:

On mobile discords symbol to expand the image nearly covers the entire key part of the image :slight_smile: and of the three together above I had to full screen the third one to see it wasn’t all white.

So? - but not solely from the picture

So are you looping backwards in a triangle because multiplication is commutative, and because you only care about the biggest one, which will probably be from the biggest numbers anyway.

So find a palindrome, make that the new biggest and then if the product of the two numbers in the loop drops below the current biggest palindrome, stop since both indexes are decreasing anyway for the inner loop.

Then if even multiplying by 999 drops you below the biggest one found then also stop the outer loop again because it’s decreasing.

1 Like

Hmm… so I googled and saw the proof for “All even-digited palindromic number % 11 == 0”, but even then, the solution is not complete, because we’re haven’t proved that the target number is even-digited?

3 Likes

I think in this specific case for 3 digit * 3 digit numbers they’ll have between the digits of 100*100=10000 which is 5 digits and 999*999=998001 which has 6 digits.

If you assume there’s an answer in between 900*900=810,000 which has six digits and 999*999 then you only need one of the six digit checks.

So some of the code that is fast in doing a reverse search or only checks a certain range presumably makes an assumption like that, unless there’s some known easy example that guarantee an answer in a particular range :slight_smile:

Or well you can try it and if it works it works and if it doesn’t you modify it :stuck_out_tongue:

I was trying to come with examples that were 1001*x where x is a three digit number such that 7*x<1000, since 1001=7*143, it it shifts and copies a three digit number into six digit one :slight_smile:

Eg a number like 101*7*143=101,101 Which is also 101*1001=101*1000 +101=101000+101.

So there is a six digit one at least eg 707*143 above. So then you can use the six digit checks if you search above this :slight_smile:

2 Likes

Yes I believe the algorithm in question relies on the assumption that the solution has exactly 6 digits.

The residue when dividing by eleven can be computed by repeatedly calculating the sum of digits with alternating sign until the result lies between -10 and +10. For example 5050567 → 7 - 6 + 5 - 0 + 5 - 0 + 5 = 16 → 5

For any palindrome with even number of digits the alternating sum is zero. However this is just a necessary condition, not a sufficient one, hence the condition is also applied to certain digit-sub-sequences (e.g. check if ABCDEF is divisible by 11, then check BCDE and then CD)

2 Likes

Wait isn’t this feel exactly like a for loop compare?

for(int i=0; i<=number.length/2; i++) {
  if(numer[i] != number[number.length - 1 - i]) return false;
}

The only difference is the method you described assume the number is 6-digits…

1 Like

Yes, I believe this can be implemented in various ways. Anyway this is just my interpretation of this condition in Glunkolins code:

3 Likes

number from your example seems to be an array (which x is not in glunkolin’s algorithm)

Though yes, you’re right one could just compare digits instead of modulo’ing 11.

1 Like

I think I remember this being explained once on Numberphile.

Perhaps it was in this video.

New problem.

2520 is the smallest number that can be divided by each of the numbers from 1 to 10 without any remainder.

What is the smallest positive number that is evenly divisible by all of the numbers from 1 to 20?

Easy, no? Should we pretty much skip this?

Looks like you just give it the equation 16 * 9 * 5 * 7 * 11 * 13 * 17 * 19, without any coding even being involved. That’s 232,792,560.

But I suppose there’s fun in making a function to work on any number. Even in that case, I wouldn’t be doing any big modulus loops: rather, I’d still just have the code produce a list of key factors like this and multiply them.

Could always code a solution that takes arbitrary N instead of fixed 20…

Also I think I’ve seen something called project euler + with wider limits around if any of these are too easy. Idk if that’s just a hackerrank.com thing or what though.

Could always code a solution that takes arbitrary N instead of fixed 20…

Yeah, that’s what I said in the spoiler.

Hmm, I think I know how I’d do it in Python, except I seem to remember that Python is weirdly funny about modifying lists sometimes…

Ah oops missed that part

By the way, shame there’s no built in Python function for checking if a number is prime. You have to use sympy or numpy or some other external.

I think Common Lisp does have a built in, called prime-p.

Generalised Python solution
from functools import reduce;

def is_prime(n):
    if n < 2: return False;
    
    elif n % 2 == 0:
        if n == 2: return True;

        else: return False;

    for i in range(3, n, 2):
        if n % i == 0: return False;

    return True;

def max_exponents_under(n):
    
    maxPrimeExpList = [];
    primeExpList = [];
    primeExp = 0;
    expt = 2;

    if n < 2:
        return [n];

    for i in range(2, n + 1, 1):
        
        # Record exponents of new primes
            
        if is_prime(i) and (not (i in primeExpList)): 
            primeExp = i;
            expt = 2;
            
            while primeExp <= n:
                primeExpList.append(primeExp);
                primeExp = i ** expt;
                expt += 1;
            
            maxPrimeExpList.append(i ** (expt - 2));

    return maxPrimeExpList;

def smallest_multiple_of_numbers_below(n):
    numsToMultiply = max_exponents_under(n);

    if len(numsToMultiply) >= 2:
        return reduce(lambda x, y: x * y, max_exponents_under(n));

    else: return numsToMultiply[0];

print(smallest_multiple_of_numbers_below(20));
1 Like
Problem 5, Python
def gcd(a, b):
    while b: a, b = b, a % b
    return a

d = 1

for n in range(2, 21):
    d *= n // gcd(d, n)

print(d)
3 Likes
Problem 6, Python
sum([n**3-n**2 for n in range(101)])

Using this identity to save some typing :slight_smile:

The visual proof is beautiful:

3 Likes