Skip to content

Commit

Permalink
[Hacker Rank]: Project Euler #3: Largest prime factor. Solved ✓.
Browse files Browse the repository at this point in the history
  • Loading branch information
Gonzalo Diaz committed Sep 27, 2024
1 parent b11f02a commit d16a9d2
Show file tree
Hide file tree
Showing 5 changed files with 182 additions and 0 deletions.
63 changes: 63 additions & 0 deletions docs/hackerrank/projecteuler/euler003-solution-notes.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
# About the **Largest prime factor** solution

## Brute force method

> [!WARNING]
>
> The penalty of this method is that it requires a large number of iterations as
> the number grows.
The first solution, using the algorithm taught in school, is:

> Start by choosing a number $ i $ starting with $ 2 $ (the smallest prime number)
> Test the divisibility of the number $ n $ by $ i $, next for each one:
>
>> - If $ n $ is divisible by $ i $, then the result is
>> the new number $ n $ is reduced, while at the same time
>> the largest number $i$ found is stored.
>>
>> - If $ n $ IS NOT divisible by $ i $, $i$ is incremented by 1
> up to $ n $.
>
> Finally:
>>
>> - If you reach the end without finding any, it is because the number $n$
>> is prime and would be the only factual prime it has.
>>
>> - Otherwise, then the largest number $i$ found would be the largest prime factor.
## Second approach, limiting to half iterations

> [!CAUTION]
>
> Using some test entries, quickly broke the solution at all. So, don't use it.
> This note is just to record the failed idea.
Since by going through and proving the divisibility of a number $ i $ up to $ n $
there are also "remainder" numbers that are also divisible by their opposite,
let's call it $ j $.

At first it seemed attractive to test numbers $ i $ up to half of $ n $ then
test whether $ i $ or $ j $ are prime. 2 problems arise:

- Testing whether a number is prime could involve increasing the number of
iterations since now the problem would become O(N^2) complex in the worst cases

- Discarding all $ j $ could mean discarding the correct solution.

Both problems were detected when using different sets of test inputs.

## Final solution using some optimization

> [!WARNING]
>
> No source was found with a mathematical proof proving that the highest prime
> factor of a number n (non-prime) always lies under the limit of $ \sqrt{n} $
A solution apparently accepted in the community as an optimization of the first
brute force algorithm consists of limiting the search to $ \sqrt{n} $.

Apparently it is a mathematical conjecture without proof
(if it exists, please send it to me).

Found the correct result in all test cases.
43 changes: 43 additions & 0 deletions docs/hackerrank/projecteuler/euler003.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# [Largest prime factor](https://www.hackerrank.com/contests/projecteuler/challenges/euler003)

- Difficulty: #easy
- Category: #ProjectEuler+

The prime factors of $ 13195 $ are $ 5 $, $ 7 $, $ 13 $ and $ 29 $.

What is the largest prime factor of a given number $ N $ ?

## Input Format

First line contains $ T $, the number of test cases. This is
followed by $ T $ lines each containing an integer $ N $.

## Constraints

- $ 1 \leq T \leq 10 $
- $ 10 \leq N \leq 10^{12} $

## Output Format

Print the required answer for each test case.

## Sample Input 0

```text
2
10
17
```

## Sample Output 0

```text
5
17
```

## Explanation 0

- Prime factors of $ 10 $ are $ {2, 5} $, largest is $ 5 $.

- Prime factor of $ 17 $ is $ 17 $ itselft, hence largest is $ 17 $.
33 changes: 33 additions & 0 deletions src/hackerrank/projecteuler/euler003.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { describe, expect, it } from '@jest/globals';
import { logger as console } from '../../logger';

import { euler003 } from './euler003';

import TEST_CASES from './euler003.testcases.json';

describe('euler003', () => {
it('euler003 JSON Test cases', () => {
expect.assertions(2);

TEST_CASES.forEach((test) => {
const calculated = euler003(test.n);
console.log(`euler003(${test.n}) solution found: ${test.expected}`);

expect(`${calculated}`).toBe(`${test.expected}`);
});
});

it('euler003 Edge case', () => {
expect.assertions(2);

const expectedMessage = 'n must be greater than 2';

expect(() => {
euler003(0);
}).toThrow(expectedMessage);

expect(() => {
euler003(1);
}).toThrow(expectedMessage);
});
});
4 changes: 4 additions & 0 deletions src/hackerrank/projecteuler/euler003.testcases.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
[
{ "n": 10, "expected": 5 },
{ "n": 17, "expected": 17 }
]
39 changes: 39 additions & 0 deletions src/hackerrank/projecteuler/euler003.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/**
* @link Problem definition [[docs/hackerrank/projecteuler/euler003.md]]
*/

import { BigIntMath } from '../lib/BigIntMath';

export function primeFactor(n: bigint): bigint {
if (n < 2) {
throw new Error('n must be greater than 2');
}

let divisor: bigint = n;
let maxPrimeFactor: bigint = divisor;
let mpfInitialized = false;

let i = 2n;

while (i <= BigIntMath.sqrt(divisor)) {
if (divisor % i === 0n) {
divisor /= i;
maxPrimeFactor = divisor;
mpfInitialized = true;
} else {
i += 1n;
}
}

if (!mpfInitialized) {
return n;
}

return maxPrimeFactor;
}

export function euler003(n: number): bigint {
return primeFactor(BigInt(n));
}

export default { euler003 };

0 comments on commit d16a9d2

Please sign in to comment.