From cee037899f4779ab750afdc66a3b9639e83c0e64 Mon Sep 17 00:00:00 2001 From: Gonzalo Diaz Date: Tue, 24 Sep 2024 00:30:12 -0300 Subject: [PATCH] =?UTF-8?q?[Hacker=20Rank]:=20Project=20Euler=20#3:=20Larg?= =?UTF-8?q?est=20prime=20factor.=20Solved=20=E2=9C=93?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../projecteuler/euler003-solution-notes.md | 63 +++++++++++++++++++ docs/hackerrank/projecteuler/euler003.md | 43 +++++++++++++ .../hackerrank/projecteuler/euler003.hpp | 7 +++ .../src/hackerrank/projecteuler/euler003.cpp | 43 +++++++++++++ .../hackerrank/projecteuler/euler003.test.cpp | 33 ++++++++++ .../projecteuler/euler003.testcases.json | 4 ++ 6 files changed, 193 insertions(+) create mode 100644 docs/hackerrank/projecteuler/euler003-solution-notes.md create mode 100644 docs/hackerrank/projecteuler/euler003.md create mode 100644 src/lib/exercises/include/exercises/hackerrank/projecteuler/euler003.hpp create mode 100644 src/lib/exercises/src/hackerrank/projecteuler/euler003.cpp create mode 100644 src/tests/unit/lib/hackerrank/projecteuler/euler003.test.cpp create mode 100644 src/tests/unit/lib/hackerrank/projecteuler/euler003.testcases.json diff --git a/docs/hackerrank/projecteuler/euler003-solution-notes.md b/docs/hackerrank/projecteuler/euler003-solution-notes.md new file mode 100644 index 0000000..24828ec --- /dev/null +++ b/docs/hackerrank/projecteuler/euler003-solution-notes.md @@ -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. diff --git a/docs/hackerrank/projecteuler/euler003.md b/docs/hackerrank/projecteuler/euler003.md new file mode 100644 index 0000000..af878d6 --- /dev/null +++ b/docs/hackerrank/projecteuler/euler003.md @@ -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 $. diff --git a/src/lib/exercises/include/exercises/hackerrank/projecteuler/euler003.hpp b/src/lib/exercises/include/exercises/hackerrank/projecteuler/euler003.hpp new file mode 100644 index 0000000..2551d8a --- /dev/null +++ b/src/lib/exercises/include/exercises/hackerrank/projecteuler/euler003.hpp @@ -0,0 +1,7 @@ +#pragma once + +namespace hackerrank::projecteuler { + +long euler003(long n); + +} // namespace hackerrank::projecteuler diff --git a/src/lib/exercises/src/hackerrank/projecteuler/euler003.cpp b/src/lib/exercises/src/hackerrank/projecteuler/euler003.cpp new file mode 100644 index 0000000..f83c1dc --- /dev/null +++ b/src/lib/exercises/src/hackerrank/projecteuler/euler003.cpp @@ -0,0 +1,43 @@ +#include + +/** + * @link Problem definition [[docs/hackerrank/projecteuler/euler003.md]] + */ + +#include +#include + +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(i) <= + std::sqrt(static_cast(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 diff --git a/src/tests/unit/lib/hackerrank/projecteuler/euler003.test.cpp b/src/tests/unit/lib/hackerrank/projecteuler/euler003.test.cpp new file mode 100644 index 0000000..143fe86 --- /dev/null +++ b/src/tests/unit/lib/hackerrank/projecteuler/euler003.test.cpp @@ -0,0 +1,33 @@ +#include + +#include +#include +#include + +#include +#include +#include +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); +} diff --git a/src/tests/unit/lib/hackerrank/projecteuler/euler003.testcases.json b/src/tests/unit/lib/hackerrank/projecteuler/euler003.testcases.json new file mode 100644 index 0000000..44db00b --- /dev/null +++ b/src/tests/unit/lib/hackerrank/projecteuler/euler003.testcases.json @@ -0,0 +1,4 @@ +[ + { "n": 10, "expected": 5 }, + { "n": 17, "expected": 17 } +]