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 24, 2024
1 parent 6946b9d commit cee0378
Show file tree
Hide file tree
Showing 6 changed files with 193 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 $.
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#pragma once

namespace hackerrank::projecteuler {

long euler003(long n);

} // namespace hackerrank::projecteuler
43 changes: 43 additions & 0 deletions src/lib/exercises/src/hackerrank/projecteuler/euler003.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
#include <exercises/hackerrank/projecteuler/euler003.hpp>

/**
* @link Problem definition [[docs/hackerrank/projecteuler/euler003.md]]
*/

#include <cmath>
#include <stdexcept>

namespace hackerrank::projecteuler {

long prime_factor(long n) {
if (n < 2) {
throw std::invalid_argument("n must be greater than 2");
}

long divisor = n;
long max_prime_factor;
bool mpf_initialized = false;

long i = 2;

while (static_cast<double>(i) <=
std::sqrt(static_cast<long double>(divisor))) {
if (0 == divisor % i) {
divisor = divisor / i;
max_prime_factor = divisor;
mpf_initialized = true;
} else {
i += 1;
}
}

if (!mpf_initialized) {
return n;
}

return max_prime_factor;
}

long euler003(long n) { return prime_factor(n); }

} // namespace hackerrank::projecteuler
33 changes: 33 additions & 0 deletions src/tests/unit/lib/hackerrank/projecteuler/euler003.test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
#include <catch2/catch_test_macros.hpp>

#include <exercises/hackerrank/projecteuler/euler003.hpp>
#include <iostream>
#include <vector>

#include <filesystem>
#include <fstream>
#include <nlohmann/json.hpp>
using json = nlohmann::json;

TEST_CASE("euler003 JSON Test Cases",
"[hackerrank] [jsontestcase] [projecteuler]") {
std::filesystem::path cwd = std::filesystem::current_path();
std::string path =
cwd.string() +
"/unit/lib/hackerrank/projecteuler/euler003.testcases.json";

INFO("euler003 JSON test cases FILE: " << path);

std::ifstream f(path);
json data = json::parse(f);

for (auto testcase : data) {
long result = hackerrank::projecteuler::euler003(testcase["n"]);
CHECK(result == testcase["expected"]);
}
}

TEST_CASE("euler003 Edge Cases", "[hackerrank] [projecteuler]") {
CHECK_THROWS_AS(hackerrank::projecteuler::euler003(0), std::invalid_argument);
CHECK_THROWS_AS(hackerrank::projecteuler::euler003(1), std::invalid_argument);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
[
{ "n": 10, "expected": 5 },
{ "n": 17, "expected": 17 }
]

0 comments on commit cee0378

Please sign in to comment.