Skip to content

Commit 9659867

Browse files
authored
Merge pull request #538 from sir-gon/feature/euler003
Feature/euler003
2 parents 7a1c05c + bcb1ecc commit 9659867

File tree

8 files changed

+259
-4
lines changed

8 files changed

+259
-4
lines changed
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
# About the **Largest prime factor** solution
2+
3+
## Brute force method
4+
5+
> [!WARNING]
6+
>
7+
> The penalty of this method is that it requires a large number of iterations as
8+
> the number grows.
9+
10+
The first solution, using the algorithm taught in school, is:
11+
12+
> Start by choosing a number $ i $ starting with $ 2 $ (the smallest prime number)
13+
> Test the divisibility of the number $ n $ by $ i $, next for each one:
14+
>
15+
>> - If $ n $ is divisible by $ i $, then the result is
16+
>> the new number $ n $ is reduced, while at the same time
17+
>> the largest number $i$ found is stored.
18+
>>
19+
>> - If $ n $ IS NOT divisible by $ i $, $i$ is incremented by 1
20+
> up to $ n $.
21+
>
22+
> Finally:
23+
>>
24+
>> - If you reach the end without finding any, it is because the number $n$
25+
>> is prime and would be the only factual prime it has.
26+
>>
27+
>> - Otherwise, then the largest number $i$ found would be the largest prime factor.
28+
29+
## Second approach, limiting to half iterations
30+
31+
> [!CAUTION]
32+
>
33+
> Using some test entries, quickly broke the solution at all. So, don't use it.
34+
> This note is just to record the failed idea.
35+
36+
Since by going through and proving the divisibility of a number $ i $ up to $ n $
37+
there are also "remainder" numbers that are also divisible by their opposite,
38+
let's call it $ j $.
39+
40+
At first it seemed attractive to test numbers $ i $ up to half of $ n $ then
41+
test whether $ i $ or $ j $ are prime. 2 problems arise:
42+
43+
- Testing whether a number is prime could involve increasing the number of
44+
iterations since now the problem would become O(N^2) complex in the worst cases
45+
46+
- Discarding all $ j $ could mean discarding the correct solution.
47+
48+
Both problems were detected when using different sets of test inputs.
49+
50+
## Final solution using some optimization
51+
52+
> [!WARNING]
53+
>
54+
> No source was found with a mathematical proof proving that the highest prime
55+
> factor of a number n (non-prime) always lies under the limit of $ \sqrt{n} $
56+
57+
A solution apparently accepted in the community as an optimization of the first
58+
brute force algorithm consists of limiting the search to $ \sqrt{n} $.
59+
60+
Apparently it is a mathematical conjecture without proof
61+
(if it exists, please send it to me).
62+
63+
Found the correct result in all test cases.
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
# [Largest prime factor](https://www.hackerrank.com/contests/projecteuler/challenges/euler003)
2+
3+
- Difficulty: #easy
4+
- Category: #ProjectEuler+
5+
6+
The prime factors of $ 13195 $ are $ 5 $, $ 7 $, $ 13 $ and $ 29 $.
7+
8+
What is the largest prime factor of a given number $ N $ ?
9+
10+
## Input Format
11+
12+
First line contains $ T $, the number of test cases. This is
13+
followed by $ T $ lines each containing an integer $ N $.
14+
15+
## Constraints
16+
17+
- $ 1 \leq T \leq 10 $
18+
- $ 10 \leq N \leq 10^{12} $
19+
20+
## Output Format
21+
22+
Print the required answer for each test case.
23+
24+
## Sample Input 0
25+
26+
```text
27+
2
28+
10
29+
17
30+
```
31+
32+
## Sample Output 0
33+
34+
```text
35+
5
36+
17
37+
```
38+
39+
## Explanation 0
40+
41+
- Prime factors of $ 10 $ are $ {2, 5} $, largest is $ 5 $.
42+
43+
- Prime factor of $ 17 $ is $ 17 $ itselft, hence largest is $ 17 $.

jest.config.js

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,7 @@ const jestConfig = {
2929
coverageDirectory: 'coverage',
3030

3131
// An array of regexp pattern strings used to skip coverage collection
32-
// coveragePathIgnorePatterns: [
33-
// "/node_modules/"
34-
// ],
32+
coveragePathIgnorePatterns: ['/node_modules/', 'src/hackerrank/lib'],
3533

3634
// Indicates which provider should be used to instrument code for coverage
3735
coverageProvider: 'v8',

sonar-project.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ sonar.organization=sir-gon
88

99
# Path is relative to the sonar-project.properties file. Replace "\" by "/" on Windows.
1010
sonar.sources=src
11-
sonar.exclusions=**/*.json,**/*.test.js,**/*.bruteforce-test.js,src/logger.js
11+
sonar.exclusions=**/*.json,**/*.test.js,**/*.bruteforce-test.js,**/lib/*,src/logger.js
1212

1313
# Encoding of the source code. Default is default system encoding
1414
sonar.sourceEncoding=UTF-8

src/hackerrank/lib/BigIntMath.js

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
/* istanbul ignore file */
2+
3+
export class BigIntMath {
4+
static max(...values) {
5+
if (values.length === 0) {
6+
return null;
7+
}
8+
9+
if (values.length === 1) {
10+
return values[0];
11+
}
12+
13+
let max = values[0];
14+
for (let i = 1; i < values.length; i++) {
15+
if (values[i] > max) {
16+
max = values[i];
17+
}
18+
}
19+
return max;
20+
}
21+
22+
static min(...values) {
23+
if (values.length === 0) {
24+
return null;
25+
}
26+
27+
if (values.length === 1) {
28+
return values[0];
29+
}
30+
31+
let min = values[0];
32+
for (let i = 1; i < values.length; i++) {
33+
if (values[i] < min) {
34+
min = values[i];
35+
}
36+
}
37+
return min;
38+
}
39+
40+
static sign(value) {
41+
if (value > 0n) {
42+
return 1n;
43+
}
44+
if (value < 0n) {
45+
return -1n;
46+
}
47+
return 0n;
48+
}
49+
50+
static abs(value) {
51+
if (this.sign(value) === -1n) {
52+
return -value;
53+
}
54+
return value;
55+
}
56+
57+
// https://stackoverflow.com/questions/53683995/javascript-big-integer-square-root/58863398#58863398
58+
static rootNth(value, k = 2n) {
59+
if (value < 0n) {
60+
throw Error('negative number is not supported');
61+
}
62+
63+
let o = 0n;
64+
let x = value;
65+
let limit = 100;
66+
67+
while (x ** k !== k && x !== o && limit > 0) {
68+
limit -= 1;
69+
o = x;
70+
x = ((k - 1n) * x + value / x ** (k - 1n)) / k;
71+
}
72+
73+
return x;
74+
}
75+
76+
static sqrt(value) {
77+
return BigIntMath.rootNth(value);
78+
}
79+
}
80+
81+
export default { BigIntMath };
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
/**
2+
* @link Problem definition [[docs/hackerrank/projecteuler/euler003.md]]
3+
*/
4+
5+
import { BigIntMath } from '../lib/BigIntMath.js';
6+
7+
export function primeFactor(n) {
8+
if (n < 2) {
9+
throw new Error('n must be greater than 2');
10+
}
11+
12+
let divisor = n;
13+
let maxPrimeFactor = divisor;
14+
15+
let i = 2n;
16+
17+
while (i <= BigIntMath.sqrt(divisor)) {
18+
if (divisor % i === 0n) {
19+
divisor /= i;
20+
maxPrimeFactor = divisor;
21+
} else {
22+
i += 1n;
23+
}
24+
}
25+
26+
return maxPrimeFactor;
27+
}
28+
29+
export function euler003(n) {
30+
return primeFactor(BigInt(n));
31+
}
32+
33+
export default { euler003 };
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import { describe, expect, it } from '@jest/globals';
2+
import { logger as console } from '../../logger.js';
3+
4+
import { euler003 } from './euler003.js';
5+
6+
import TEST_CASES from './euler003.testcases.json';
7+
8+
describe('euler003', () => {
9+
it('euler003 JSON Test cases', () => {
10+
expect.assertions(2);
11+
12+
TEST_CASES.forEach((test) => {
13+
const calculated = euler003(test.n);
14+
console.log(`euler003(${test.n}) solution found: ${test.expected}`);
15+
16+
expect(`${calculated}`).toBe(`${test.expected}`);
17+
});
18+
});
19+
20+
it('euler003 Edge case', () => {
21+
expect.assertions(2);
22+
23+
const expectedMessage = 'n must be greater than 2';
24+
25+
expect(() => {
26+
euler003(0);
27+
}).toThrow(expectedMessage);
28+
29+
expect(() => {
30+
euler003(1);
31+
}).toThrow(expectedMessage);
32+
});
33+
});
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
[
2+
{ "n": 10, "expected": 5 },
3+
{ "n": 17, "expected": 17 }
4+
]

0 commit comments

Comments
 (0)